home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / vm / sun4.md / vmSun.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-19  |  158.1 KB  |  5,601 lines

  1. /*
  2.  * vmSun.c -
  3.  *
  4.  *         This file contains all hardware-dependent vm C routines for Sun2's, 3's 
  5.  *    and 4's.  I will not attempt to explain the Sun mapping hardware in 
  6.  *    here.  See the sun architecture manuals for details on
  7.  *    the mapping hardware.
  8.  *
  9.  * Copyright 1990 Regents of the University of California
  10.  * Permission to use, copy, modify, and distribute this
  11.  * software and its documentation for any purpose and without
  12.  * fee is hereby granted, provided that the above copyright
  13.  * notice appear in all copies.  The University of California
  14.  * makes no representations about the suitability of this
  15.  * software for any purpose.  It is provided "as is" without
  16.  * express or implied warranty.
  17.  */
  18.  
  19. #ifndef lint
  20. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/vm/sun4.md/vmSun.c,v 9.44 92/10/26 12:02:12 elm Exp $ SPRITE (Berkeley)";
  21. #endif not lint
  22.  
  23. #include <sprite.h>
  24. #include <vmSunConst.h>
  25. #include <machMon.h>
  26. #include <vm.h>
  27. #include <vmInt.h>
  28. #include <vmMach.h>
  29. #include <vmMachInt.h>
  30. #include <list.h>
  31. #include <mach.h>
  32. #include <proc.h>
  33. #include <sched.h>
  34. #include <stdlib.h>
  35. #include <sync.h>
  36. #include <sys.h>
  37. #include <dbg.h>
  38. #include <net.h>
  39. #include <stdio.h>
  40. #include <bstring.h>
  41. #include <recov.h>
  42.  
  43. #if (MACH_MAX_NUM_PROCESSORS == 1) /* uniprocessor implementation */
  44. #undef MASTER_LOCK
  45. #undef MASTER_UNLOCK
  46. #define MASTER_LOCK(x) DISABLE_INTR()
  47. #define MASTER_UNLOCK(x) ENABLE_INTR()
  48. #else
  49.  
  50. /*
  51.  * The master lock to synchronize access to pmegs and context.
  52.  */
  53. static Sync_Semaphore vmMachMutex;
  54. static Sync_Semaphore *vmMachMutexPtr = &vmMachMutex;
  55. #endif
  56.  
  57. #ifndef sun4c
  58. /*
  59.  * Macros to translate from a virtual page to a physical page and back.
  60.  * For the sun4c, these are no longer macros, since they are much more
  61.  * complicated due to physical memory no longer being contiguous.  For
  62.  * speed perhaps someday they should be converted to complicated macros
  63.  * instead of functions.
  64.  */
  65. #define VirtToPhysPage(pfNum) ((pfNum) << VMMACH_CLUSTER_SHIFT)
  66. #define PhysToVirtPage(pfNum) ((pfNum) >> VMMACH_CLUSTER_SHIFT)
  67. #endif
  68.  
  69. extern int debugVmStubs; /* Unix compat debug flag. */
  70.  
  71. /*
  72.  * Convert from page to hardware segment, with correction for
  73.  * any difference between virtAddrPtr offset and segment offset.
  74.  * (This difference will only happen for shared segments.)
  75. */
  76. #define PageToOffSeg(page,virtAddrPtr) (PageToSeg((page)- \
  77.     segOffset(virtAddrPtr)+(virtAddrPtr->segPtr->offset)))
  78.  
  79. extern    Address    vmStackEndAddr;
  80.  
  81. static int GetNumPages _ARGS_((void));
  82. static int GetNumValidPages _ARGS_((Address virtAddr));
  83. static void FlushValidPages _ARGS_ ((Address virtAddr));
  84. #ifdef sun4c
  85. static int VirtToPhysPage _ARGS_((int pfNum));
  86. static int PhysToVirtPage _ARGS_((int pfNum));
  87. #endif /* sun4c */
  88. static void VmMachSetSegMapInContext _ARGS_((unsigned int context,
  89.     Address addr, unsigned int pmeg));
  90. static void MMUInit _ARGS_((int firstFreeSegment));
  91. ENTRY static void CopySegData _ARGS_((register Vm_Segment *segPtr,
  92.     register VmMach_SegData *oldSegDataPtr,
  93.     register VmMach_SegData *newSegDataPtr));
  94. static void SegDelete _ARGS_((Vm_Segment *segPtr));
  95. INTERNAL static int PMEGGet _ARGS_((Vm_Segment  *softSegPtr, int hardSegNum,
  96.     Boolean flags));
  97. INTERNAL static void PMEGFree _ARGS_((int pmegNum));
  98. ENTRY static Boolean PMEGLock _ARGS_ ((register VmMach_SegData *machPtr,
  99.     int segNum));
  100. INTERNAL static void SetupContext _ARGS_((register Proc_ControlBlock
  101.     *procPtr));
  102. static void InitNetMem _ARGS_((void));
  103. ENTRY static void WriteHardMapSeg _ARGS_((VmMach_ProcData *machPtr));
  104. static void PageInvalidate _ARGS_((register Vm_VirtAddr *virtAddrPtr,
  105.     unsigned int virtPage, Boolean segDeletion));
  106. INTERNAL static void DevBufferInit _ARGS_((void));
  107. static void VmMachTrap _ARGS_((void));
  108. #ifndef sun4c
  109. INTERNAL static void Dev32BitDMABufferInit _ARGS_((void));
  110. #endif
  111.  
  112. /*----------------------------------------------------------------------
  113.  * 
  114.  *             Hardware data structures
  115.  *
  116.  * Terminology: 
  117.  *    1) Physical page frame: A frame that contains one hardware page.
  118.  *    2) Virtual page frame:  A frame that contains VMMACH_CLUSTER_SIZE 
  119.  *                hardware pages.
  120.  *    3) Software segment: The segment structure used by the hardware
  121.  *                 independent VM module.
  122.  *    4) Hardware segment: A piece of a hardware context.
  123.  *
  124.  * A hardware context corresponds to a process's address space.  A context
  125.  * is made up of many equal sized hardware segments.  The 
  126.  * kernel is mapped into each hardware context so that the kernel has easy
  127.  * access to user data.  One context (context 0) is reserved for use by
  128.  * kernel processes.  The hardware contexts are defined by the array
  129.  * contextArray which contains an entry for each context.  Each entry 
  130.  * contains a pointer back to the process that is executing in the context 
  131.  * and an array which is an exact duplicate of the hardware segment map for
  132.  * the context.  The contexts are managed by keeping all contexts except for
  133.  * the system context in a list that is kept in LRU order.  Whenever a context 
  134.  * is needed the first context off of the list is used and the context is
  135.  * stolen from the current process that owns it if necessary.
  136.  *
  137.  * PMEGs are allocated to software segments in order to allow pages to be mapped
  138.  * into the segment's virtual address space. There are only a few hundred
  139.  * PMEGs, which have to be shared by all segments.  PMEGs that have
  140.  * been allocated to user segments can be stolen at any time.  PMEGs that have
  141.  * been allocated to the system segment cannot be taken away unless the system
  142.  * segment voluntarily gives it up.  In order to manage the PMEGs there are
  143.  * two data structures.  One is an array of PMEG info structures that contains
  144.  * one entry for each PMEG.  The other is an array stored with each software
  145.  * segment struct that contains the PMEGs that have been allocated to the
  146.  * software segment.  Each entry in the array of PMEG info structures
  147.  * contains enough information to remove the PMEG from its software segment.
  148.  * One of the fields in the PMEG info struct is the count of pages that have
  149.  * been validated in the PMEG.  This is used to determine when a PMEG is no
  150.  * longer being actively used.  
  151.  *
  152.  * There are two lists that are used to manage PMEGs.  The pmegFreeList 
  153.  * contains all PMEGs that are either not being used or contain no valid 
  154.  * page map entries; unused ones are inserted at the front of the list 
  155.  * and empty ones at the rear.  The pmegInuseList contains all PMEGs
  156.  * that are being actively used to map user segments and is managed as a FIFO.
  157.  * PMEGs that are being used to map tbe kernel's VAS do not appear on the 
  158.  * pmegInuseList. When a pmeg is needed to map a virtual address, first the
  159.  * free list is checked.  If it is not empty then the first PMEG is pulled 
  160.  * off of the list.  If it is empty then the first PMEG is pulled off of the
  161.  * inUse list.  If the PMEG  that is selected is being used (either actively 
  162.  * or inactively) then it is freed from the software segment that is using it.
  163.  * Once the PMEG is freed up then if it is being allocated for a user segment
  164.  * it is put onto the end of the pmegInuseList.
  165.  *
  166.  * Page frames are allocated to software segments even when there is
  167.  * no PMEG to map it in.  Thus when a PMEG that was mapping a page needs to
  168.  * be removed from the software segment that owns the page, the reference
  169.  * and modify bits stored in the PMEG for the page must be saved.  The
  170.  * array refModMap is used for this.  It contains one entry for each
  171.  * virtual page frame.  Its value for a page frame or'd with the bits stored
  172.  * in the PMEG (if any) comprise the referenced and modified bits for a 
  173.  * virtual page frame.
  174.  * 
  175.  * IMPORTANT SYNCHRONIZATION NOTE:
  176.  *
  177.  * The internal data structures in this file have to be protected by a
  178.  * master lock if this code is to be run on a multi-processor.  Since a
  179.  * process cannot start executing unless VmMach_SetupContext can be
  180.  * executed first, VmMach_SetupContext cannot context switch inside itself;
  181.  * otherwise a deadlock will occur.  However, VmMach_SetupContext mucks with
  182.  * contexts and PMEGS and therefore would have to be synchronized
  183.  * on a multi-processor.  A monitor lock cannot be used because it may force
  184.  * VmMach_SetupContext to be context switched.
  185.  *
  186.  * The routines in this file also muck with other per segment data structures.
  187.  * Access to these data structures is synchronized by our caller (the
  188.  * machine independent module).
  189.  *
  190.  *----------------------------------------------------------------------
  191.  */
  192.  
  193. /*
  194.  * Machine dependent flags for the flags field in the Vm_VirtAddr struct.
  195.  * We are only allowed to use the second byte of the flags.
  196.  *
  197.  *    USING_MAPPED_SEG        The parsed virtual address falls into
  198.  *                    the mapping segment.
  199.  */
  200. #define    USING_MAPPED_SEG    0x100
  201.  
  202. /*
  203.  * Macros to get to and from hardware segments and pages.
  204.  */
  205. #define PageToSeg(page) ((page) >> (VMMACH_SEG_SHIFT - VMMACH_PAGE_SHIFT))
  206. #define SegToPage(seg) ((seg) << (VMMACH_SEG_SHIFT - VMMACH_PAGE_SHIFT))
  207.  
  208. #if (VMMACH_CLUSTER_SIZE == 1) 
  209. /*
  210.  * Macro to set all page map entries for the given virtual address.
  211.  */
  212. #define    SET_ALL_PAGE_MAP(virtAddr, pte) { \
  213.     VmMachSetPageMap((Address)(virtAddr), (pte)); \
  214. }
  215. /*
  216.  * Macro to flush all pages for the given virtual address.
  217.  */
  218. #define    FLUSH_ALL_PAGE(virtAddr) { \
  219.     VmMachFlushPage((Address)(virtAddr)); \
  220. }
  221. #else
  222. #define    SET_ALL_PAGE_MAP(virtAddr, pte) { \
  223.     int    __i; \
  224.     for (__i = 0; __i < VMMACH_CLUSTER_SIZE; __i++) { \
  225.     VmMachSetPageMap((virtAddr) + __i * VMMACH_PAGE_SIZE_INT, (pte) + __i); \
  226.     } \
  227. }
  228. #define    FLUSH_ALL_PAGE(virtAddr) { \
  229.     int    __i; \
  230.     for (__i = 0; __i < VMMACH_CLUSTER_SIZE; __i++) { \
  231.     VmMachFlushPage((virtAddr) + __i * VMMACH_PAGE_SIZE_INT); \
  232.     } \
  233. }
  234. #endif
  235.  
  236. /*
  237.  * PMEG table entry structure.
  238.  */
  239. typedef struct {
  240.     List_Links            links;        /* Links so that the pmeg */
  241.                                   /* can be in a list */
  242.     struct VmMach_PMEGseg    segInfo;    /* Info on software segment. */
  243.     int                pageCount;    /* Count of resident pages in
  244.                          * this pmeg. */
  245.     int                lockCount;    /* The number of times that
  246.                          * this PMEG has been locked.*/
  247.     int                flags;        /* Flags defined below. */
  248. } PMEG;
  249.  
  250. /*
  251.  * Flags to indicate the state of a pmeg.
  252.  *
  253.  *    PMEG_DONT_ALLOC    This pmeg should not be reallocated.  This is 
  254.  *            when a pmeg cannot be reclaimed until it is
  255.  *            voluntarily freed.
  256.  *    PMEG_NEVER_FREE    Don't ever free this pmeg no matter what anybody says.
  257.  */
  258. #define    PMEG_DONT_ALLOC        0x1
  259. #define    PMEG_NEVER_FREE        0x2
  260.  
  261. /*
  262.  * Pmeg information.  pmegArray contains one entry for each pmeg.  pmegFreeList
  263.  * is a list of all pmegs that aren't being actively used.  pmegInuseList
  264.  * is a list of all pmegs that are being actively used.
  265.  */
  266.  
  267. static    unsigned int    vmNumPmegs;
  268.     unsigned int    vmPmegMask;
  269. static    PMEG           *pmegArray;
  270. static    List_Links       pmegFreeListHeader;
  271. static    List_Links       *pmegFreeList = &pmegFreeListHeader;
  272. static    List_Links       pmegInuseListHeader;
  273. static    List_Links       *pmegInuseList = &pmegInuseListHeader;
  274.  
  275. #ifdef sun4c
  276. unsigned int    vmCacheLineSize;
  277. unsigned int    vmCacheSize;
  278. unsigned int    vmCacheShift;
  279. #endif
  280.  
  281. /*
  282.  * The context table structure.
  283.  */
  284. typedef struct VmMach_Context {
  285.     List_Links            links;     /* Links so that the contexts can be
  286.                          in a list. */
  287.     struct Proc_ControlBlock    *procPtr;    /* A pointer to the process
  288.                          * table entry for the process
  289.                          * that is running in this
  290.                          * context. */
  291.     VMMACH_SEG_NUM        map[VMMACH_NUM_SEGS_PER_CONTEXT];
  292.                     /* A reflection of the hardware context
  293.                      * map. */
  294.     unsigned int        context;/* Which context this is. */
  295.     int                flags;    /* Defined below. */
  296. } VmMach_Context;
  297.  
  298. /*
  299.  * Context flags:
  300.  *
  301.  *         CONTEXT_IN_USE    This context is used by a process.
  302.  */
  303. #define    CONTEXT_IN_USE    0x1
  304.  
  305. /*
  306.  * Context information.  contextArray contains one entry for each context. 
  307.  * contextList is a list of contexts in LRU order.
  308.  */
  309. #ifdef sun4c
  310. static    unsigned int    vmNumContexts;
  311. static    VmMach_Context    *contextArray;
  312. #else
  313. static    VmMach_Context    contextArray[VMMACH_NUM_CONTEXTS];
  314. #endif
  315. static    List_Links       contextListHeader;
  316. static    List_Links       *contextList = &contextListHeader;
  317.  
  318. /*
  319.  * Map containing one entry for each virtual page.
  320.  */
  321. static    VmMachPTE        *refModMap;
  322.  
  323. /*
  324.  * Macro to get a pointer into a software segment's hardware segment table.
  325.  */
  326. #ifdef CLEAN
  327. #define GetHardSegPtr(machPtr, segNum) \
  328.     ((machPtr)->segTablePtr + (segNum) - (machPtr)->offset)
  329. #else
  330. #define GetHardSegPtr(machPtr, segNum) \
  331.     ( ((unsigned)((segNum) - (machPtr)->offset) > (machPtr)->numSegs) ? \
  332.     (panic("Invalid segNum\n"),(machPtr)->segTablePtr) : \
  333.     ((machPtr)->segTablePtr + (segNum) - (machPtr)->offset) )
  334. #endif
  335.  
  336. /*
  337.  * Macro to check to see if address is in a hardware segment (PMEG) that
  338.  * is used by file cache virtual addresses.
  339.  * These kernel segment pmegs may be stolen.
  340.  */
  341.  
  342. #define    _ROUND2SEG(x) ((unsigned int)(x)  & ~(VMMACH_SEG_SIZE-1))
  343. #define    IN_FILE_CACHE_SEG(addr)                          \
  344.           ( ((unsigned int)(addr) >=                         \
  345.         _ROUND2SEG(vmBlockCacheBaseAddr + (VMMACH_SEG_SIZE-1))) &&   \
  346.         ((unsigned int)(addr) < _ROUND2SEG(vmBlockCacheEndAddr)) )
  347.  
  348. /*
  349.  * TRUE if stealing of file cache pmegs are permitted. Initialized to FALSE
  350.  * for backward compat with old file cache code.
  351.  */
  352. Boolean vmMachCanStealFileCachePmegs = FALSE;
  353.  
  354. /*
  355.  * The maximum amount of kernel code + data available.  This is set to however
  356.  * big you want it to be to make sure that the kernel heap has enough memory
  357.  * for all the file handles, etc.
  358.  */
  359. #ifdef sun2
  360. int    vmMachKernMemSize = 2048 * 1024;
  361. #endif
  362. #ifdef sun3
  363. int     vmMachKernMemSize = 8192 * 1024;
  364. #endif
  365. #ifdef sun4
  366. #ifdef sun4c
  367. int    vmMachKernMemSize = 32 * 1024 * 1024;
  368. #else
  369. int    vmMachKernMemSize = 40 * 1024 * 1024;
  370. #endif
  371. #endif
  372.  
  373. /*
  374.  * The segment that is used to map a segment into a process's virtual address
  375.  * space for cross-address-space copies.
  376.  */
  377. #define    MAP_SEG_NUM (((unsigned int) VMMACH_MAP_SEG_ADDR) >> VMMACH_SEG_SHIFT)
  378.  
  379. static    VmMach_SegData    *sysMachPtr;
  380. Address            vmMachPTESegAddr;
  381. Address            vmMachPMEGSegAddr;
  382.  
  383. #ifdef sun4c
  384. /*
  385.  * Structure for mapping virtual page frame numbers to physical page frame
  386.  * numbers and back for each memory board.
  387.  */
  388. typedef struct    {
  389.     unsigned int    endVirPfNum;    /* Ending virtual page frame number
  390.                      * on board. */
  391.     unsigned int    startVirPfNum;    /* Starting virtual page frame number
  392.                      * on board. */
  393.     unsigned int    physStartAddr;    /* Physical address of page frame. */
  394.     unsigned int    physEndAddr;    /* End physical address of page frame.*/
  395. } Memory_Board;
  396.  
  397. /*
  398.  * Pointer to board after last configured Memory board structure.
  399.  */
  400. static    Memory_Board    *lastMemBoard;
  401.  
  402. /*
  403.  * Memory_Board structures for each board in the system.  This array is sorted
  404.  * by endVirPfNum.
  405.  */
  406. static    Memory_Board    Mboards[6];
  407. #endif /* sun4c */
  408.  
  409. /*
  410.  * vmMachHasVACache - TRUE if the machine has a virtual address cache.
  411.  * vmMachHasHwFlush - TRUE if the machine has the hardware assist cache flush
  412.  *              option.
  413.  */
  414. Boolean    vmMachHasVACache    = TRUE;
  415. Boolean    vmMachHasHwFlush    = FALSE;
  416.  
  417. /*
  418.  * ----------------------------------------------------------------------------
  419.  *
  420.  * VmMach_BootInit --
  421.  *
  422.  *      Do hardware dependent boot time initialization.
  423.  *
  424.  * Results:
  425.  *      None.
  426.  *
  427.  * Side effects:
  428.  *      Hardware page map for the kernel is initialized.  Also the various size
  429.  *     fields are filled in.
  430.  *
  431.  * ----------------------------------------------------------------------------
  432.  */
  433. void
  434. VmMach_BootInit(pageSizePtr, pageShiftPtr, pageTableIncPtr, kernMemSizePtr,
  435.         numKernPagesPtr, maxSegsPtr, maxProcessesPtr)
  436.     int    *pageSizePtr;
  437.     int    *pageShiftPtr;
  438.     int    *pageTableIncPtr;
  439.     int    *kernMemSizePtr;
  440.     int    *numKernPagesPtr;
  441.     int    *maxSegsPtr;
  442.     int *maxProcessesPtr;
  443. {
  444.     register Address    virtAddr;
  445.     register int    i;
  446.     int            kernPages;
  447.     int            numPages;
  448. #ifdef sun4c
  449.     Mach_MemList    *memPtr;
  450.     int            nextVframeNum, numFrames;
  451. #endif
  452.  
  453. #if (MACH_MAX_NUM_PROCESSORS != 1) /* multiprocessor implementation */
  454.     Sync_SemInitDynamic(&vmMachMutex, "Vm:vmMachMutex");
  455. #endif
  456.  
  457. #ifdef sun4c
  458.     /*
  459.      * Initialize the physical to virtual page mappings, since memory isn't
  460.      * contiguous.
  461.      */
  462.     lastMemBoard = Mboards;
  463.     nextVframeNum = 0;
  464.     if (romVectorPtr->v_romvec_version >= 2) {
  465.     Mach_MemList mlist[128];
  466.     int     numMemList, i;
  467.  
  468.     numMemList = Mach_MonSearchProm("memory", "available", (char *) mlist,
  469.                     sizeof(mlist)) / sizeof(Mach_MemList);
  470.     /*
  471.      * XXX - fix this
  472.      * Currently the VM module assumes that the kernel
  473.      * is in phsyically contiguous memory. Kernel page 0 is in 
  474.      * phsyical page zero (or at least startVirPfNum == 0). The
  475.      * Prom on the 4/75 returns memlist is reverse order with
  476.      * phsical zero last.
  477.      */
  478.     for (i = numMemList - 1; i >= 0; --i) {
  479.         memPtr = mlist + i;
  480.         if (memPtr->size != 0) {
  481.         numFrames = memPtr->size / VMMACH_PAGE_SIZE;
  482.         lastMemBoard->startVirPfNum = nextVframeNum;
  483.         lastMemBoard->endVirPfNum = nextVframeNum + numFrames;
  484.         nextVframeNum += numFrames;
  485.         lastMemBoard->physStartAddr =
  486.             memPtr->address >> VMMACH_PAGE_SHIFT_INT;
  487.         lastMemBoard->physEndAddr = lastMemBoard->physStartAddr +
  488.             numFrames * VMMACH_CLUSTER_SIZE;
  489.         lastMemBoard++;
  490.         }
  491.     }
  492.     } else {
  493.     for (memPtr = *(romVectorPtr->availMemory);
  494.         memPtr != (Mach_MemList *) 0;
  495.         memPtr = memPtr->next) {
  496.         if (memPtr->size != 0) {
  497.         numFrames = memPtr->size / VMMACH_PAGE_SIZE;
  498.         lastMemBoard->startVirPfNum = nextVframeNum;
  499.         lastMemBoard->endVirPfNum = nextVframeNum + numFrames;
  500.         nextVframeNum += numFrames;
  501.         lastMemBoard->physStartAddr =
  502.             memPtr->address >> VMMACH_PAGE_SHIFT_INT;
  503.         lastMemBoard->physEndAddr = lastMemBoard->physStartAddr +
  504.             numFrames * VMMACH_CLUSTER_SIZE;
  505.         lastMemBoard++;
  506.         }
  507.     }
  508.     }
  509.     if (lastMemBoard == Mboards) {
  510.     panic("No memory boards in system configuration.");
  511.     }
  512.  
  513.     if (Mach_MonSearchProm("*", "vac-linesize", (char *)&vmCacheLineSize,
  514.         sizeof vmCacheLineSize) == -1) {
  515.     vmCacheLineSize = VMMACH_CACHE_LINE_SIZE_60;
  516.     }
  517.     vmCacheSize = VMMACH_CACHE_SIZE;    /* for assembly code */
  518.     {
  519.     unsigned i = vmCacheLineSize;
  520.     vmCacheShift = 0;
  521.     while (i >>= 1) {
  522.         ++vmCacheShift;
  523.     }
  524.     }
  525.     if (Mach_MonSearchProm("*", "vac_hwflush", (char *)&vmMachHasHwFlush,
  526.         sizeof vmMachHasHwFlush) == -1) {
  527.     vmMachHasHwFlush = FALSE;
  528.     }
  529.     if (Mach_MonSearchProm("*", "mmu-npmg", (char *)&vmNumPmegs,
  530.         sizeof vmNumPmegs) == -1) {
  531.     vmNumPmegs = VMMACH_NUM_PMEGS_60;
  532.     }
  533. #else /* sun4c */
  534.     switch (Mach_GetMachineType()) {
  535.     case SYS_SUN_4_110:
  536.         vmNumPmegs = VMMACH_NUM_PMEGS_110;
  537.         vmMachHasVACache = FALSE;
  538.         break;
  539.     case SYS_SUN_4_260:
  540.         vmNumPmegs = VMMACH_NUM_PMEGS_260;
  541.         break;
  542.     case SYS_SUN_4_330:
  543.         vmNumPmegs = VMMACH_NUM_PMEGS_330;
  544.         break;
  545.     case SYS_SUN_4_470:
  546.         vmNumPmegs = VMMACH_NUM_PMEGS_470;
  547.         break;
  548.     default:
  549.         panic("What sort of machine type is %x?\n", Mach_GetMachineType());
  550.     }
  551. #endif /* sun4c */
  552.     vmPmegMask = vmNumPmegs - 1;
  553.     
  554.     kernPages = vmMachKernMemSize / VMMACH_PAGE_SIZE_INT;
  555.     /*
  556.      * Map all of the kernel memory that we might need one for one.  We know
  557.      * that the monitor maps the first part of memory one for one but for some
  558.      * reason it doesn't map enough.  We assume that the pmegs have been
  559.      * mapped correctly.
  560.      */
  561.     for (i = 0, virtAddr = (Address)mach_KernStart; 
  562.     i < kernPages;
  563.     i++, virtAddr += VMMACH_PAGE_SIZE_INT) {
  564.     if (VmMachGetSegMap(virtAddr) != VMMACH_INV_PMEG) {
  565.         VmMachPTE pte = VmMachGetPageMap(virtAddr);
  566.         if (pte & VMMACH_RESIDENT_BIT) { 
  567.         pte &= VMMACH_PAGE_FRAME_FIELD;
  568. #ifdef sun4
  569.         pte |= VMMACH_DONT_CACHE_BIT;
  570. #endif
  571.         VmMachSetPageMap(virtAddr, 
  572.             (VmMachPTE)(VMMACH_KRW_PROT | VMMACH_RESIDENT_BIT | pte));
  573.         } else {
  574.         printf("VmMach_BootInit: Last page ends at %x.\n", virtAddr);
  575.         break;
  576.         }
  577.     } else {
  578.         printf("VmMach_BootInit: Last segment ends at %x.\n", virtAddr);
  579.         break;
  580.     }
  581.     }
  582.  
  583.     /*
  584.      * Do boot time allocation.
  585.      */
  586.     pmegArray = (PMEG *)Vm_BootAlloc(sizeof(PMEG) * vmNumPmegs);
  587. #ifdef sun4c
  588.     if (Mach_MonSearchProm("*", "mmu-nctx", (char *)&vmNumContexts,
  589.         sizeof vmNumContexts) == -1) {
  590.     vmNumContexts = VMMACH_NUM_CONTEXTS_60;
  591.     }
  592.     contextArray = (VmMach_Context *)Vm_BootAlloc(sizeof(VmMach_Context) *
  593.         vmNumContexts);
  594. #endif
  595.     sysMachPtr = (VmMach_SegData *)Vm_BootAlloc(sizeof(VmMach_SegData) + 
  596.         (sizeof (VMMACH_SEG_NUM) * VMMACH_NUM_SEGS_PER_CONTEXT));
  597.     numPages = GetNumPages();
  598.     refModMap = (VmMachPTE *)Vm_BootAlloc(sizeof(VmMachPTE) * numPages);
  599.  
  600.     /*
  601.      * Return lots of sizes to the machine independent module who called us.
  602.      */
  603.     *pageSizePtr = VMMACH_PAGE_SIZE;
  604.     *pageShiftPtr = VMMACH_PAGE_SHIFT;
  605.     *pageTableIncPtr = VMMACH_PAGE_TABLE_INCREMENT;
  606.     *kernMemSizePtr = vmMachKernMemSize;
  607.     *maxProcessesPtr = VMMACH_MAX_KERN_STACKS;
  608.     *numKernPagesPtr = numPages;
  609.     /* 
  610.      * We don't care how many software segments there are so return -1 as
  611.      * the max.
  612.      */
  613.     *maxSegsPtr = -1;
  614. }
  615.  
  616.  
  617. /*
  618.  * ----------------------------------------------------------------------------
  619.  *
  620.  * GetNumPages --
  621.  *
  622.  *     Determine how many pages of physical memory there are.
  623.  *     For the sun4c, this determines how many physical pages of memory
  624.  *     are available after the prom has grabbed some.
  625.  *
  626.  * Results:
  627.  *     The number of physical pages available.
  628.  *
  629.  * Side effects:
  630.  *     None.
  631.  *
  632.  * ----------------------------------------------------------------------------
  633.  */
  634. static int
  635. GetNumPages()
  636. {
  637. #ifdef sun4c
  638.     int    memory = 0;
  639.     Mach_MemList    *memPtr;
  640.  
  641.     if (romVectorPtr->v_romvec_version >= 2) {    
  642.     Mach_MemList mlist[128];
  643.     int     numMemList, i;
  644.  
  645.     numMemList = Mach_MonSearchProm("memory", "available", (char *) mlist,
  646.                     sizeof(mlist)) / sizeof(Mach_MemList);
  647.     for (i = 0; i < numMemList; i++) {
  648.         memPtr = mlist + i;
  649.         memory += memPtr->size / VMMACH_PAGE_SIZE;
  650.     }
  651.     } else {
  652.     for (memPtr = *(romVectorPtr->availMemory);
  653.         memPtr != (Mach_MemList *) 0;
  654.         memPtr = memPtr->next) {
  655.         memory += memPtr->size / VMMACH_PAGE_SIZE;
  656.     }
  657.     }
  658.     return memory;
  659. #else
  660.     return (*romVectorPtr->memoryAvail / VMMACH_PAGE_SIZE);
  661. #endif
  662. }
  663.  
  664. #ifdef sun4c
  665.  
  666. /*
  667.  * ----------------------------------------------------------------------------
  668.  *
  669.  * VirtToPhysPage --
  670.  *
  671.  *     Translate from a virtual page to a physical page.
  672.  *     This was a macro on the other suns, but for the sun4c, physical
  673.  *     memory isn't contiguous.
  674.  *
  675.  * Results:
  676.  *     An address.
  677.  *
  678.  * Side effects:
  679.  *     None.
  680.  *
  681.  * ----------------------------------------------------------------------------
  682.  */
  683. static int
  684. VirtToPhysPage(pfNum)
  685.     int        pfNum;
  686. {
  687.     register    Memory_Board    *mb;
  688.  
  689.     for (mb = Mboards; mb < lastMemBoard; mb++) {
  690.     if (pfNum < mb->endVirPfNum && pfNum >= mb->startVirPfNum) {
  691.         return mb->physStartAddr +
  692.         (pfNum - mb->startVirPfNum) * VMMACH_CLUSTER_SIZE;
  693.     }
  694.     }
  695.     panic("VirtToPhysPage: virtual page %x not found.\n", pfNum);
  696.     return NIL;
  697. }
  698.  
  699.  
  700. /*
  701.  * ----------------------------------------------------------------------------
  702.  *
  703.  * PhysToVirtPage --
  704.  *
  705.  *     Translate from a physical page to a virtual page.
  706.  *     This was a macro on the other suns, but for the sun4c, physical
  707.  *     memory isn't contiguous.
  708.  *
  709.  * Results:
  710.  *     An address.
  711.  *
  712.  * Side effects:
  713.  *     None.
  714.  *
  715.  * ----------------------------------------------------------------------------
  716.  */
  717. static int
  718. PhysToVirtPage(pfNum)
  719.     int        pfNum;
  720. {
  721.     register    Memory_Board    *mb;
  722.  
  723.     for (mb = Mboards; mb < lastMemBoard; mb++) {
  724.     if (pfNum >= mb->physStartAddr && pfNum < mb->physEndAddr) {
  725.         return mb->startVirPfNum +
  726.         (pfNum - mb->physStartAddr) / VMMACH_CLUSTER_SIZE;
  727.     }
  728.     }
  729.     panic("PhysToVirtPage: physical page %x not found.\n", pfNum);
  730.     return NIL;
  731. }
  732. #endif /* sun4c */
  733.  
  734.  
  735. /*
  736.  * ----------------------------------------------------------------------------
  737.  *
  738.  * VmMachSetSegMapInContext --
  739.  *
  740.  *    Set the segment map in a context that may not yet be mapped without
  741.  *    causing a fault.  So far, this is only useful on the sun4c.
  742.  *
  743.  * Results:
  744.  *     None.
  745.  *
  746.  * Side effects:
  747.  *     The segment map in another context is modified..
  748.  *
  749.  * ----------------------------------------------------------------------------
  750.  */
  751. static void
  752. VmMachSetSegMapInContext(context, addr, pmeg)
  753.     unsigned    int    context;
  754.     Address        addr;
  755.     unsigned    int    pmeg;
  756. {
  757. #ifdef sun4
  758.     /* This matters for a 4/110 */
  759.     if (!VMMACH_ADDR_CHECK(addr)) {
  760.     addr += VMMACH_TOP_OF_HOLE - VMMACH_BOTTOM_OF_HOLE + 1;
  761.     }
  762. #endif
  763.     romVectorPtr->SetSegInContext(context, addr, pmeg);
  764.     return;
  765. }
  766.  
  767.  
  768. /*
  769.  * ----------------------------------------------------------------------------
  770.  *
  771.  * VmMach_AllocKernSpace --
  772.  *
  773.  *     Allocate memory for machine dependent stuff in the kernels VAS.
  774.  *
  775.  * Results:
  776.  *     None.  Well, it returns something, Mike...  It seems to return the
  777.  *     address of the next free area.
  778.  *
  779.  * Side effects:
  780.  *     None.
  781.  *
  782.  * ----------------------------------------------------------------------------
  783.  */
  784. Address
  785. VmMach_AllocKernSpace(baseAddr)
  786.     Address    baseAddr;
  787. {
  788.     /*
  789.      * If the base address is at the beginning of a segment, we just want
  790.      * to allocate this segment for vmMachPTESegAddr.  If base addr is partway
  791.      * into a segment, we want a whole segment, so move to the next segment
  792.      * to allocate that one.  (baseAddr + VMMACH_SEG_SIZE - 1) moves us to
  793.      * next segment unless we were at the very beginning of one.  Then divide
  794.      * by VMMACH_SEG_SIZE to get segment number.  Then multiply by
  795.      * VMMACH_SEG_SIZE to get address of the begginning of the segment.
  796.      */
  797.     baseAddr = (Address) ((((unsigned int)baseAddr + VMMACH_SEG_SIZE - 1) / 
  798.                     VMMACH_SEG_SIZE) * VMMACH_SEG_SIZE);
  799.     vmMachPTESegAddr = baseAddr;    /* first seg for Pte mapping */
  800.     vmMachPMEGSegAddr = baseAddr + VMMACH_SEG_SIZE;    /* next for pmegs */
  801.     return(baseAddr + 2 * VMMACH_SEG_SIZE);    /* end of allocated area */
  802. }
  803.  
  804.  
  805. /*
  806.  * ----------------------------------------------------------------------------
  807.  *
  808.  * VmMach_Init --
  809.  *
  810.  *     Initialize all virtual memory data structures.
  811.  *
  812.  * Results:
  813.  *     None.
  814.  *
  815.  * Side effects:
  816.  *     All virtual memory linked lists and arrays are initialized.
  817.  *
  818.  * ----------------------------------------------------------------------------
  819.  */
  820. void
  821. VmMach_Init(firstFreePage)
  822.     int    firstFreePage;    /* Virtual page that is the first free for the 
  823.              * kernel. */
  824. {
  825.     register    int         i;
  826.     int             firstFreeSegment;
  827.     Address            virtAddr;
  828.     Address            lastCodeAddr;
  829.     extern    int        etext;
  830.     VMMACH_SEG_NUM        pmeg;
  831.  
  832.     /*
  833.      * Initialize the kernel's hardware segment table.
  834.      */
  835.     vm_SysSegPtr->machPtr = sysMachPtr;
  836.     sysMachPtr->numSegs = VMMACH_NUM_SEGS_PER_CONTEXT;
  837.     sysMachPtr->offset = PageToSeg(vm_SysSegPtr->offset);
  838.     sysMachPtr->segTablePtr =
  839.         (VMMACH_SEG_NUM *) ((Address)sysMachPtr + sizeof(VmMach_SegData));
  840.     for (i = 0; i < VMMACH_NUM_SEGS_PER_CONTEXT; i++) {
  841.     sysMachPtr->segTablePtr[i] = VMMACH_INV_PMEG;
  842.     }
  843.  
  844.     /*
  845.      * Determine which hardware segment is the first that is not in use.
  846.      */
  847.     firstFreeSegment = ((firstFreePage - 1) << VMMACH_PAGE_SHIFT) / 
  848.                     VMMACH_SEG_SIZE + 1;
  849.     firstFreeSegment += (unsigned int)mach_KernStart >> VMMACH_SEG_SHIFT;
  850.  
  851.     /* 
  852.      * Initialize the PMEG and context tables and lists.
  853.      */
  854.     MMUInit(firstFreeSegment);
  855.  
  856.     /*
  857.      * Initialize the page map.
  858.      */
  859.     bzero((Address)refModMap, sizeof(VmMachPTE) * GetNumPages());
  860.  
  861.     /*
  862.      * The code segment is read only and all other in use kernel memory
  863.      * is read/write.  Since the loader may put the data in the same page
  864.      * as the last code page, the last code page is also read/write.
  865.      */
  866.     lastCodeAddr = (Address) ((unsigned)&etext - VMMACH_PAGE_SIZE);
  867.     for (i = 0, virtAddr = (Address)mach_KernStart;
  868.         i < firstFreePage;
  869.         virtAddr += VMMACH_PAGE_SIZE, i++) {
  870.     register VmMachPTE pte;
  871.     register int physPage;
  872.  
  873.     physPage = VirtToPhysPage(i);
  874.     {
  875.         int j;
  876.  
  877.         for (j = 0; j < VMMACH_CLUSTER_SIZE; ++j) {
  878.         pte = VmMachGetPageMap(virtAddr + j * VMMACH_PAGE_SIZE_INT)
  879.             & VMMACH_PAGE_FRAME_FIELD;
  880.         if (pte != physPage + j) {
  881.             panic("VmMach_Init: weird mapping %x != %x\n",
  882.             pte, physPage + j);
  883.         }
  884.         }
  885.     }
  886.  
  887.     if (recov_Transparent && virtAddr >= (Address) mach_RestartTablePtr &&
  888.         virtAddr <
  889.         ((Address) mach_RestartTablePtr + Mach_GetRestartTableSize())) {
  890.         pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT | physPage;
  891.     } else if (virtAddr >= (Address)MACH_CODE_START &&
  892.         virtAddr <= lastCodeAddr) {
  893.         pte = VMMACH_RESIDENT_BIT | VMMACH_KR_PROT | physPage;
  894.     } else {
  895.         pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT | physPage;
  896. #ifdef sun4
  897.         if (virtAddr >= vmStackEndAddr) {
  898.         pte |= VMMACH_DONT_CACHE_BIT;
  899.         }
  900. #endif /* sun4 */
  901.     }
  902.     SET_ALL_PAGE_MAP(virtAddr, pte);
  903.     }
  904.  
  905.     /*
  906.      * Protect the bottom of the kernel stack.
  907.      */
  908.     SET_ALL_PAGE_MAP((Address)mach_StackBottom, (VmMachPTE)0);
  909.  
  910.     /*
  911.      * Invalid until the end of the last segment
  912.      */
  913.     for (;virtAddr < (Address) (firstFreeSegment << VMMACH_SEG_SHIFT);
  914.      virtAddr += VMMACH_PAGE_SIZE) {
  915.     SET_ALL_PAGE_MAP(virtAddr, (VmMachPTE)0);
  916.     }
  917.  
  918.     /* 
  919.      * Zero out the invalid pmeg.
  920.      */
  921.     /* Need I flush something? */
  922.     VmMachPMEGZero(VMMACH_INV_PMEG);
  923.  
  924.     /*
  925.      * Finally copy the kernel's context to each of the other contexts.
  926.      */
  927.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  928.     int        segNum;
  929.  
  930.     if (i == VMMACH_KERN_CONTEXT) {
  931.         continue;
  932.     }
  933. #ifdef NOTDEF
  934.     VmMachSetUserContext(i);
  935.     for (segNum = ((unsigned int) mach_KernStart) / VMMACH_SEG_SIZE,
  936.          segTablePtr = vm_SysSegPtr->machPtr->segTablePtr;
  937.          segNum < VMMACH_NUM_SEGS_PER_CONTEXT;
  938.          segNum++, segTablePtr++) {
  939.  
  940.         virtAddr = (Address) (segNum * VMMACH_SEG_SIZE);
  941.         /*
  942.          * No need to flush stuff since the other contexts haven't
  943.          * been used yet.
  944.          */
  945.         VmMachSetSegMap(virtAddr, (int)*segTablePtr);
  946.     }
  947. #else
  948.     /*
  949.      * For the sun4c, there is currently a problem just copying things
  950.      * out of the segTable, so do it from the real hardware.  I need to
  951.      * figure out what's wrong.
  952.      */
  953.     for (segNum = ((unsigned int) mach_KernStart) / VMMACH_SEG_SIZE;
  954.          segNum < VMMACH_NUM_SEGS_PER_CONTEXT; segNum++) {
  955.  
  956.         virtAddr = (Address) (segNum * VMMACH_SEG_SIZE);
  957. #ifdef KERNEL_NOT_ABOVE_HOLE
  958.         if (!VMMACH_ADDR_CHECK(virtAddr)) {
  959.         continue;
  960.         }
  961. #endif
  962.         pmeg = VmMachGetSegMap(virtAddr);
  963.         VmMachSetSegMapInContext((unsigned char) i, virtAddr, pmeg);
  964.     }
  965. #endif
  966.     }
  967. #ifdef NOTDEF
  968.     VmMachSetUserContext(VMMACH_KERN_CONTEXT);
  969. #endif
  970. #ifndef sun4
  971.     if (Mach_GetMachineType() == SYS_SUN_3_50) {
  972.     unsigned int vidPage;
  973.  
  974. #define    VIDEO_START    0x100000    /* From Sun3 architecture manual */
  975. #define    VIDEO_SIZE    0x20000
  976.     vidPage = VIDEO_START / VMMACH_PAGE_SIZE;
  977.     if (firstFreePage > vidPage) {
  978.         panic("VmMach_Init: We overran video memory.\n");
  979.     }
  980.     /*
  981.      * On 3/50's the display is kept in main memory beginning at 1 
  982.      * Mbyte and going for 128 kbytes.  Reserve this memory so VM
  983.      * doesn't try to use it.
  984.      */
  985.     for (;vidPage < (VIDEO_START + VIDEO_SIZE) / VMMACH_PAGE_SIZE;
  986.          vidPage++) {
  987.         Vm_ReservePage(vidPage);
  988.     }
  989.     }
  990. #endif /* sun4 */
  991.     /*
  992.      * Turn on caching.
  993.      */
  994.     if (vmMachHasVACache) {
  995.     VmMachClearCacheTags();
  996.     }
  997. #ifndef sun4c
  998.     VmMachInitAddrErrorControlReg();
  999. #endif
  1000.     VmMachInitSystemEnableReg();
  1001. }
  1002.  
  1003.  
  1004. /*
  1005.  *----------------------------------------------------------------------
  1006.  *
  1007.  * MMUInit --
  1008.  *
  1009.  *    Initialize the context table and lists and the Pmeg table and 
  1010.  *    lists.
  1011.  *
  1012.  * Results:
  1013.  *    None.
  1014.  *
  1015.  * Side effects:
  1016.  *    Context table and Pmeg table are initialized.  Also context list
  1017.  *    and pmeg list are initialized.
  1018.  *
  1019.  *----------------------------------------------------------------------
  1020.  */
  1021. static void
  1022. MMUInit(firstFreeSegment)
  1023.     int        firstFreeSegment;
  1024. {
  1025.     register    int        i;
  1026.     register    PMEG        *pmegPtr;
  1027.     register    VMMACH_SEG_NUM    *segTablePtr;
  1028.     VMMACH_SEG_NUM        pageCluster;
  1029.  
  1030.     /*
  1031.      * Initialize the context table.
  1032.      */
  1033.     contextArray[VMMACH_KERN_CONTEXT].flags = CONTEXT_IN_USE;
  1034.     List_Init(contextList);
  1035.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  1036.     if (i != VMMACH_KERN_CONTEXT) {
  1037.         contextArray[i].flags = 0;
  1038.         List_Insert((List_Links *) &contextArray[i], 
  1039.             LIST_ATREAR(contextList));
  1040.     }
  1041.     contextArray[i].context = i;
  1042.     }
  1043.  
  1044.     /*
  1045.      * Initialize the page cluster list.
  1046.      */
  1047.     List_Init(pmegFreeList);
  1048.     List_Init(pmegInuseList);
  1049.  
  1050.     /*
  1051.      * Initialize the pmeg structure.
  1052.      */
  1053.     bzero((Address)pmegArray, VMMACH_NUM_PMEGS * sizeof(PMEG));
  1054.     for (i = 0, pmegPtr = pmegArray; i < VMMACH_NUM_PMEGS; i++, pmegPtr++) {
  1055.     pmegPtr->segInfo.segPtr = (Vm_Segment *) NIL;
  1056.     pmegPtr->flags = PMEG_DONT_ALLOC;
  1057.     pmegPtr->segInfo.nextLink = (struct VmMach_PMEGseg *)NIL;
  1058.     }
  1059.  
  1060. #ifdef sun2
  1061.     /*
  1062.      * Segment 0 is left alone because it is required for the monitor.
  1063.      */
  1064.     pmegArray[0].segPtr = (Vm_Segment *)NIL;
  1065.     pmegArray[0].hardSegNum = 0;
  1066.     i = 1;
  1067. #else
  1068.     i = 0;
  1069. #endif /* sun2 */
  1070.  
  1071.     /*
  1072.      * Invalidate all hardware segments from first segment up to the beginning
  1073.      * of the kernel.
  1074.      */
  1075.     for (; i < ((((unsigned int) mach_KernStart) & VMMACH_ADDR_MASK) >>
  1076.         VMMACH_SEG_SHIFT); i++) {
  1077.     int    j;
  1078.     Address    addr;
  1079.  
  1080.     addr = (Address) (i << VMMACH_SEG_SHIFT);
  1081.     /*
  1082.      * Copy the invalidation to all the other contexts, so that
  1083.      * the user contexts won't have double-mapped pmegs at the low-address
  1084.      * segments.
  1085.      */
  1086.     for (j = 0; j < VMMACH_NUM_CONTEXTS; j++) {
  1087.         /* Yes, do this here since user stuff would be double mapped. */
  1088.         VmMachSetSegMapInContext((unsigned char) j, addr,
  1089.             (unsigned char) VMMACH_INV_PMEG);
  1090.     }
  1091.     }
  1092.     i = ((unsigned int) mach_KernStart >> VMMACH_SEG_SHIFT);
  1093.  
  1094.     /*
  1095.      * Reserve all pmegs that have kernel code or heap.
  1096.      */
  1097.     for (segTablePtr = vm_SysSegPtr->machPtr->segTablePtr;
  1098.          i < firstFreeSegment;
  1099.      i++, segTablePtr++) {
  1100.     pageCluster = VmMachGetSegMap((Address) (i << VMMACH_SEG_SHIFT));
  1101.     pmegArray[pageCluster].pageCount = VMMACH_NUM_PAGES_PER_SEG;
  1102.     pmegArray[pageCluster].segInfo.segPtr = vm_SysSegPtr;
  1103.     pmegArray[pageCluster].segInfo.hardSegNum = i;
  1104.     *segTablePtr = pageCluster;
  1105.     }
  1106.  
  1107.     /*
  1108.      * Invalidate all hardware segments that aren't in code or heap and are 
  1109.      * before the specially mapped page clusters.
  1110.      */
  1111.     for (; i < VMMACH_FIRST_SPECIAL_SEG; i++, segTablePtr++) {
  1112.     Address    addr;
  1113.     /* Yes, do this here, since user stuff would be double-mapped. */
  1114.     addr = (Address) (i << VMMACH_SEG_SHIFT);
  1115.     VmMachSetSegMap(addr, VMMACH_INV_PMEG);
  1116.     }
  1117.  
  1118.     /*
  1119.      * Mark the invalid pmeg so that it never gets used.
  1120.      */
  1121.     pmegArray[VMMACH_INV_PMEG].segInfo.segPtr = vm_SysSegPtr;
  1122.     pmegArray[VMMACH_INV_PMEG].flags = PMEG_NEVER_FREE;
  1123.  
  1124.     /*
  1125.      * Now reserve the rest of the page clusters that have been set up by
  1126.      * the monitor.  Don't reserve any PMEGs that don't have any valid 
  1127.      * mappings in them.
  1128.      */
  1129.     for (; i < VMMACH_NUM_SEGS_PER_CONTEXT; i++, segTablePtr++) {
  1130.     Address        virtAddr;
  1131.     int        j;
  1132.     VmMachPTE    pte;
  1133.     Boolean        inusePMEG;
  1134.  
  1135.     virtAddr = (Address) (i << VMMACH_SEG_SHIFT);
  1136.         if ((virtAddr >= (Address)VMMACH_DMA_START_ADDR) &&
  1137.         (virtAddr < (Address)(VMMACH_DMA_START_ADDR+VMMACH_DMA_SIZE))) {
  1138.         /*
  1139.          * Blow away anything in DMA space. 
  1140.          */
  1141.         pageCluster = VMMACH_INV_PMEG;
  1142.         VmMachSetSegMap(virtAddr, VMMACH_INV_PMEG);
  1143.     } else {
  1144.         pageCluster = VmMachGetSegMap(virtAddr);
  1145.         if (pageCluster != VMMACH_INV_PMEG) {
  1146.         inusePMEG = FALSE;
  1147.         for (j = 0; 
  1148.              j < VMMACH_NUM_PAGES_PER_SEG_INT; 
  1149.              j++, virtAddr += VMMACH_PAGE_SIZE_INT) {
  1150.             pte = VmMachGetPageMap(virtAddr);
  1151.             if ((pte & VMMACH_RESIDENT_BIT) &&
  1152.             (pte & (VMMACH_TYPE_FIELD|VMMACH_PAGE_FRAME_FIELD)) != 0) {
  1153.             /*
  1154.              * A PMEG contains a valid mapping if the resident
  1155.              * bit is set and the page frame and type field
  1156.              * are non-zero.  On Sun 2/50's the PROM sets
  1157.              * the resident bit but leaves the page frame equal
  1158.              * to zero.
  1159.              */
  1160.             if (!inusePMEG) {
  1161.                 pmegArray[pageCluster].segInfo.segPtr =
  1162.                     vm_SysSegPtr;
  1163.                 pmegArray[pageCluster].segInfo.hardSegNum = i;
  1164.                 pmegArray[pageCluster].flags = PMEG_NEVER_FREE;
  1165.                 inusePMEG = TRUE;
  1166.             }
  1167.             } else {
  1168.             VmMachSetPageMap(virtAddr, (VmMachPTE)0);
  1169.             }
  1170.         }
  1171.         virtAddr -= VMMACH_SEG_SIZE;
  1172.         if (!inusePMEG ||
  1173.             (virtAddr >= (Address)VMMACH_DMA_START_ADDR &&
  1174.              virtAddr < (Address)(VMMACH_DMA_START_ADDR+VMMACH_DMA_SIZE))) {
  1175.             VmMachSetSegMap(virtAddr, VMMACH_INV_PMEG);
  1176.             pageCluster = VMMACH_INV_PMEG;
  1177.         }
  1178.         }
  1179.     }
  1180.     *segTablePtr = pageCluster;
  1181.     }
  1182.  
  1183. #if defined (sun3)
  1184.     /*
  1185.      * We can't use the hardware segment that corresponds to the
  1186.      * last segment of physical memory for some reason.  Zero it out
  1187.      * and can't reboot w/o powering the machine off.
  1188.      */
  1189.     dontUse = (*romVectorPtr->memoryAvail - 1) / VMMACH_SEG_SIZE;
  1190. #endif
  1191.  
  1192.     /*
  1193.      * Now finally, all page clusters that have a NIL segment pointer are
  1194.      * put onto the page cluster fifo.  On a Sun-3 one hardware segment is 
  1195.      * off limits for some reason.  Zero it out and can't reboot w/o 
  1196.      * powering the machine off.
  1197.      */
  1198.     for (i = 0, pmegPtr = pmegArray; i < VMMACH_NUM_PMEGS; i++, pmegPtr++) {
  1199.  
  1200.     if (pmegPtr->segInfo.segPtr == (Vm_Segment *) NIL 
  1201. #if defined (sun3)
  1202.         && i != dontUse
  1203. #endif
  1204.     ) {
  1205.         List_Insert((List_Links *) pmegPtr, LIST_ATREAR(pmegFreeList));
  1206.         pmegPtr->flags = 0;
  1207.         VmMachPMEGZero(i);
  1208.     }
  1209.     }
  1210. }
  1211.  
  1212.  
  1213. /*
  1214.  * ----------------------------------------------------------------------------
  1215.  *
  1216.  * VmMach_SegInit --
  1217.  *
  1218.  *      Initialize hardware dependent data for a segment.
  1219.  *
  1220.  * Results:
  1221.  *      None.
  1222.  *
  1223.  * Side effects:
  1224.  *      Machine dependent data struct and is allocated and initialized.
  1225.  *
  1226.  * ----------------------------------------------------------------------------
  1227.  */
  1228. void
  1229. VmMach_SegInit(segPtr)
  1230.     Vm_Segment    *segPtr;
  1231. {
  1232.     register    VmMach_SegData    *segDataPtr;
  1233.     int                segTableSize;
  1234.     int        i;
  1235.  
  1236.     if (segPtr->type == VM_CODE) {
  1237.     segTableSize =
  1238.         (segPtr->ptSize + segPtr->offset + VMMACH_NUM_PAGES_PER_SEG - 1) / 
  1239.                             VMMACH_NUM_PAGES_PER_SEG;
  1240.     } else {
  1241.     segTableSize = segPtr->ptSize / VMMACH_NUM_PAGES_PER_SEG;
  1242.     }
  1243.     segDataPtr = (VmMach_SegData *)malloc(sizeof(VmMach_SegData) +
  1244.     (segTableSize * sizeof (VMMACH_SEG_NUM)));
  1245.  
  1246.     segDataPtr->numSegs = segTableSize;
  1247.     segDataPtr->offset = PageToSeg(segPtr->offset);
  1248.     segDataPtr->segTablePtr =
  1249.         (VMMACH_SEG_NUM *) ((Address)segDataPtr + sizeof(VmMach_SegData));
  1250.     segDataPtr->pmegInfo.inuse = 0;
  1251.     for (i = 0; i < segTableSize; i++) {
  1252.     segDataPtr->segTablePtr[i] = VMMACH_INV_PMEG;
  1253.     }
  1254.     segPtr->machPtr = segDataPtr;
  1255.     /*
  1256.      * Set the minimum and maximum virtual addresses for this segment to
  1257.      * be as small and as big as possible respectively because things will
  1258.      * be prevented from growing automatically as soon as segments run into
  1259.      * each other.
  1260.      */
  1261.     segPtr->minAddr = (Address)0;
  1262.     segPtr->maxAddr = (Address)0xffffffff;
  1263. }
  1264.  
  1265.  
  1266. /*
  1267.  *----------------------------------------------------------------------
  1268.  *
  1269.  * VmMach_SegExpand --
  1270.  *
  1271.  *    Allocate more space for the machine dependent structure.
  1272.  *
  1273.  * Results:
  1274.  *    None.
  1275.  *
  1276.  * Side effects:
  1277.  *    Memory allocated for a new hardware segment table.
  1278.  *
  1279.  *----------------------------------------------------------------------
  1280.  */
  1281. /*ARGSUSED*/
  1282. void
  1283. VmMach_SegExpand(segPtr, firstPage, lastPage)
  1284.     register    Vm_Segment    *segPtr;    /* Segment to expand. */
  1285.     int                firstPage;    /* First page to add. */
  1286.     int                lastPage;    /* Last page to add. */
  1287. {
  1288.     int                newSegTableSize;
  1289.     register    VmMach_SegData    *oldSegDataPtr;
  1290.     register    VmMach_SegData    *newSegDataPtr;
  1291.  
  1292.     newSegTableSize = (segPtr->ptSize + VMMACH_NUM_PAGES_PER_SEG-1 +
  1293.         (segPtr->offset%VMMACH_NUM_PAGES_PER_SEG)) /
  1294.         VMMACH_NUM_PAGES_PER_SEG;
  1295.     oldSegDataPtr = segPtr->machPtr;
  1296.     if (newSegTableSize <= oldSegDataPtr->numSegs) {
  1297.     return;
  1298.     }
  1299.     newSegDataPtr = 
  1300.     (VmMach_SegData *)malloc(sizeof(VmMach_SegData) + (newSegTableSize *
  1301.         sizeof (VMMACH_SEG_NUM)));
  1302.     newSegDataPtr->numSegs = newSegTableSize;
  1303.     newSegDataPtr->offset = PageToSeg(segPtr->offset);
  1304.     newSegDataPtr->segTablePtr = (VMMACH_SEG_NUM *) ((Address)newSegDataPtr +
  1305.             sizeof(VmMach_SegData));
  1306.     CopySegData(segPtr, oldSegDataPtr, newSegDataPtr);
  1307.     free((Address)oldSegDataPtr);
  1308. }
  1309.  
  1310.  
  1311. /*
  1312.  *----------------------------------------------------------------------
  1313.  *
  1314.  * CopySegData --
  1315.  *
  1316.  *    Copy over the old hardware segment data into the new expanded
  1317.  *    structure.
  1318.  *
  1319.  * Results:
  1320.  *    None.
  1321.  *
  1322.  * Side effects:
  1323.  *    The hardware segment table is copied.
  1324.  *
  1325.  *----------------------------------------------------------------------
  1326.  */
  1327. ENTRY static void
  1328. CopySegData(segPtr, oldSegDataPtr, newSegDataPtr)
  1329.     register    Vm_Segment    *segPtr;    /* The segment to add the
  1330.                            virtual pages to. */
  1331.     register    VmMach_SegData    *oldSegDataPtr;
  1332.     register    VmMach_SegData    *newSegDataPtr;
  1333. {
  1334.     int        i, j;
  1335.  
  1336.     MASTER_LOCK(vmMachMutexPtr);
  1337.  
  1338.     if (segPtr->type == VM_HEAP) {
  1339.     /*
  1340.      * Copy over the hardware segment table into the lower part
  1341.      * and set the rest to invalid.
  1342.      */
  1343.     bcopy((Address)oldSegDataPtr->segTablePtr,
  1344.         (Address)newSegDataPtr->segTablePtr,
  1345.         oldSegDataPtr->numSegs * sizeof (VMMACH_SEG_NUM));
  1346.     j = newSegDataPtr->numSegs - oldSegDataPtr->numSegs;
  1347.  
  1348.     for (i = 0; i < j; i++) {
  1349.         newSegDataPtr->segTablePtr[oldSegDataPtr->numSegs + i]
  1350.             = VMMACH_INV_PMEG;
  1351.     }
  1352.     } else {
  1353.     /*
  1354.      * Copy the current segment table into the high part of the
  1355.      * new segment table and set the lower part to invalid.
  1356.      */
  1357.     bcopy((Address)oldSegDataPtr->segTablePtr,
  1358.         (Address)(newSegDataPtr->segTablePtr + 
  1359.         newSegDataPtr->numSegs - oldSegDataPtr->numSegs),
  1360.         oldSegDataPtr->numSegs * sizeof (VMMACH_SEG_NUM));
  1361.     j = newSegDataPtr->numSegs - oldSegDataPtr->numSegs;
  1362.  
  1363.     for (i = 0; i < j; i++) {
  1364.         newSegDataPtr->segTablePtr[i] = VMMACH_INV_PMEG;
  1365.     }
  1366.     }
  1367.     segPtr->machPtr = newSegDataPtr;
  1368.  
  1369.     MASTER_UNLOCK(vmMachMutexPtr);
  1370. }
  1371.  
  1372.  
  1373. /*
  1374.  * ----------------------------------------------------------------------------
  1375.  *
  1376.  * VmMach_SegDelete --
  1377.  *
  1378.  *      Free hardware dependent resources for this software segment.
  1379.  *
  1380.  * Results:
  1381.  *      None.
  1382.  *
  1383.  * Side effects:
  1384.  *      Machine dependent struct freed and the pointer in the segment
  1385.  *    is set to NIL.
  1386.  *
  1387.  * ----------------------------------------------------------------------------
  1388.  */
  1389. void
  1390. VmMach_SegDelete(segPtr)
  1391.     register    Vm_Segment    *segPtr;    /* Pointer to segment to free. */
  1392. {
  1393.     SegDelete(segPtr);
  1394.     free((Address)segPtr->machPtr);
  1395.     segPtr->machPtr = (VmMach_SegData *)NIL;
  1396.     if (segPtr->type==VM_SHARED && debugVmStubs) {
  1397.     printf("Done with seg %d\n", segPtr->segNum);
  1398.     }
  1399. }
  1400.  
  1401.  
  1402. /*
  1403.  * ----------------------------------------------------------------------------
  1404.  *
  1405.  * SegDelete --
  1406.  *
  1407.  *      Free up any pmegs used by this segment.
  1408.  *
  1409.  * Results:
  1410.  *      None.
  1411.  *
  1412.  * Side effects:
  1413.  *      All pmegs used by this segment are freed.
  1414.  *
  1415.  * ----------------------------------------------------------------------------
  1416.  */
  1417. ENTRY static void
  1418. SegDelete(segPtr)
  1419.     Vm_Segment    *segPtr;    /* Pointer to segment to free. */
  1420. {
  1421.     register    int         i;
  1422.     register    VMMACH_SEG_NUM    *pmegPtr;
  1423.     register    VmMach_SegData    *machPtr;
  1424.  
  1425.     MASTER_LOCK(vmMachMutexPtr);
  1426.  
  1427.     machPtr = segPtr->machPtr;
  1428.     for (i = 0, pmegPtr = (VMMACH_SEG_NUM *) machPtr->segTablePtr;
  1429.          i < machPtr->numSegs; i++, pmegPtr++) {
  1430.     if (*pmegPtr != VMMACH_INV_PMEG) {
  1431.         /* Flushing is done in PMEGFree */
  1432.         PMEGFree((int) *pmegPtr);
  1433.     }
  1434.     }
  1435.  
  1436.     MASTER_UNLOCK(vmMachMutexPtr);
  1437. }
  1438.  
  1439.  
  1440. /*
  1441.  *----------------------------------------------------------------------
  1442.  *
  1443.  * VmMach_GetContext --
  1444.  *
  1445.  *    Return the context for a process, given its pcb.
  1446.  *
  1447.  * Results:
  1448.  *    Context number for process. -1 if the process doesn't
  1449.  *    have a context allocated.
  1450.  *
  1451.  * Side effects:
  1452.  *    None.
  1453.  *
  1454.  *----------------------------------------------------------------------
  1455.  */
  1456. int
  1457. VmMach_GetContext(procPtr)
  1458.     Proc_ControlBlock    *procPtr;
  1459. {
  1460.     VmMach_Context    *contextPtr;
  1461.     contextPtr = procPtr->vmPtr->machPtr->contextPtr;
  1462.     return ((contextPtr == (VmMach_Context *)NIL) ? -1 : contextPtr->context);
  1463. }
  1464.  
  1465.  
  1466. /*
  1467.  *----------------------------------------------------------------------
  1468.  *
  1469.  * VmMach_ProcInit --
  1470.  *
  1471.  *    Initalize the machine dependent part of the VM proc info.
  1472.  *
  1473.  * Results:
  1474.  *    None.
  1475.  *
  1476.  * Side effects:
  1477.  *    Machine dependent proc info is initialized.
  1478.  *
  1479.  *----------------------------------------------------------------------
  1480.  */
  1481. void
  1482. VmMach_ProcInit(vmPtr)
  1483.     register    Vm_ProcInfo    *vmPtr;
  1484. {
  1485.     if (vmPtr->machPtr == (VmMach_ProcData *)NIL) {
  1486.     vmPtr->machPtr = (VmMach_ProcData *)malloc(sizeof(VmMach_ProcData));
  1487.     }
  1488.     vmPtr->machPtr->contextPtr = (VmMach_Context *)NIL;
  1489.     vmPtr->machPtr->mapSegPtr = (struct Vm_Segment *)NIL;
  1490.     vmPtr->machPtr->sharedData.allocVector = (int *)NIL;
  1491. }
  1492.  
  1493.  
  1494. /*
  1495.  * ----------------------------------------------------------------------------
  1496.  *
  1497.  * PMEGGet --
  1498.  *
  1499.  *      Return the next pmeg from the list of available pmegs.  If the 
  1500.  *      lock flag is set then the pmeg is removed from the pmeg list.
  1501.  *      Otherwise it is moved to the back.
  1502.  *
  1503.  * Results:
  1504.  *      The pmeg number that is allocated.
  1505.  *
  1506.  * Side effects:
  1507.  *      A pmeg is either removed from the pmeg list or moved to the back.
  1508.  *
  1509.  * ----------------------------------------------------------------------------
  1510.  */
  1511. INTERNAL static int
  1512. PMEGGet(softSegPtr, hardSegNum, flags)
  1513.     Vm_Segment     *softSegPtr;    /* Which software segment this is. */
  1514.     int        hardSegNum;    /* Which hardware segment in the software 
  1515.                    segment that this is */
  1516.     Boolean    flags;        /* Flags that indicate the state of the pmeg. */
  1517. {
  1518.     register PMEG        *pmegPtr;
  1519.     register Vm_Segment        *segPtr;
  1520.     register VmMachPTE        *ptePtr;
  1521.     register VmMach_Context    *contextPtr;
  1522.     register int        i;
  1523.     register VmMachPTE        hardPTE;
  1524.     VmMachPTE            pteArray[VMMACH_NUM_PAGES_PER_SEG_INT];
  1525.     int                     oldContext;
  1526.     int                pmegNum;
  1527.     Address            virtAddr;
  1528.     Boolean            found = FALSE;
  1529.     int                numValidPages;
  1530.     struct VmMach_PMEGseg    *curSeg, *nextSeg;
  1531.  
  1532.     if (List_IsEmpty(pmegFreeList)) {
  1533.     
  1534.     LIST_FORALL(pmegInuseList, (List_Links *)pmegPtr) {
  1535.         if (pmegPtr->lockCount == 0) {
  1536.         found = TRUE;
  1537.         break;
  1538.         }
  1539.     }
  1540.     if (!found) {
  1541.         panic("Pmeg lists empty\n");
  1542.         return(VMMACH_INV_PMEG);
  1543.     }
  1544.     } else {
  1545.     pmegPtr = (PMEG *)List_First(pmegFreeList);
  1546.     }
  1547.     pmegNum = pmegPtr - pmegArray;
  1548.  
  1549.     oldContext = VmMachGetContextReg();
  1550.     if (pmegPtr->segInfo.segPtr != (Vm_Segment *) NIL) {
  1551.     /*
  1552.      * Need to steal the pmeg from its current owner.
  1553.      */
  1554.     for (curSeg = &pmegPtr->segInfo; curSeg != (struct VmMach_PMEGseg *)NIL;) {
  1555.         vmStat.machDepStat.stealPmeg++;
  1556.         segPtr = curSeg->segPtr;
  1557.         *GetHardSegPtr(segPtr->machPtr, curSeg->hardSegNum) =
  1558.             VMMACH_INV_PMEG;
  1559.         virtAddr = (Address) (curSeg->hardSegNum << VMMACH_SEG_SHIFT);
  1560.         /*
  1561.          * Delete the pmeg from all appropriate contexts.
  1562.          */
  1563.         if (segPtr->type == VM_SYSTEM) {
  1564.         /*
  1565.          * For cache accesses of data with the supervisor tag set,
  1566.          * the flush only needs to be done in one context.
  1567.          */
  1568.         numValidPages = GetNumValidPages(virtAddr);
  1569.         if (numValidPages >
  1570.             (VMMACH_CACHE_SIZE / VMMACH_PAGE_SIZE_INT)) {
  1571.             if (vmMachHasVACache) {
  1572.             VmMachFlushSegment(virtAddr);
  1573.             }
  1574.         } else {
  1575.             /* flush the pages */
  1576.             FlushValidPages(virtAddr);
  1577.         }
  1578.  
  1579.         for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  1580.             VmMachSetContextReg(i);
  1581.             VmMachSetSegMap(virtAddr, VMMACH_INV_PMEG);
  1582.         }
  1583.         } else {
  1584.         for (i = 1, contextPtr = &contextArray[1];
  1585.              i < VMMACH_NUM_CONTEXTS; 
  1586.              i++, contextPtr++) {
  1587.             if (contextPtr->flags & CONTEXT_IN_USE) {
  1588.             if (contextPtr->map[curSeg->hardSegNum] ==
  1589.                 pmegNum) {
  1590.                 VmMachSetContextReg(i);
  1591.                 contextPtr->map[curSeg->hardSegNum] =
  1592.                     VMMACH_INV_PMEG;
  1593.                 numValidPages = GetNumValidPages(virtAddr);
  1594.                 if (numValidPages >
  1595.                     (VMMACH_CACHE_SIZE / VMMACH_PAGE_SIZE_INT)) {
  1596.                 if (vmMachHasVACache) {
  1597.                     VmMachFlushSegment(virtAddr);
  1598.                 }
  1599.                 } else {
  1600.                 /* flush the pages */
  1601.                 FlushValidPages(virtAddr);
  1602.                 }
  1603.                 VmMachSetSegMap(virtAddr, VMMACH_INV_PMEG);
  1604.             }
  1605.             if (contextPtr->map[MAP_SEG_NUM] == pmegNum) {
  1606.                 VmMachSetContextReg(i);
  1607.                 contextPtr->map[MAP_SEG_NUM] = VMMACH_INV_PMEG;
  1608.                 if (vmMachHasVACache) {
  1609.                 VmMachFlushSegment((Address)VMMACH_MAP_SEG_ADDR);
  1610.                 }
  1611.                 VmMachSetSegMap((Address)VMMACH_MAP_SEG_ADDR,
  1612.                         VMMACH_INV_PMEG);
  1613.             }
  1614.             }
  1615.         }
  1616.         }
  1617.         nextSeg = curSeg->nextLink;
  1618.         if (curSeg != &pmegPtr->segInfo) {
  1619.         curSeg->inuse = 0;
  1620.         }
  1621.         curSeg = nextSeg;
  1622.     }
  1623.     pmegPtr->segInfo.nextLink = (struct VmMach_PMEGseg *)NIL;
  1624.     VmMachSetContextReg(oldContext);
  1625.     /*
  1626.      * Read out all reference and modify bits from the pmeg.
  1627.      */
  1628.     if (pmegPtr->pageCount > 0) {
  1629.         ptePtr = pteArray;
  1630.         VmMachReadAndZeroPMEG(pmegNum, ptePtr);
  1631.         for (i = 0;
  1632.          i < VMMACH_NUM_PAGES_PER_SEG_INT;
  1633.          i++, ptePtr++) {
  1634.         hardPTE = *ptePtr;
  1635.         if ((hardPTE & VMMACH_RESIDENT_BIT) &&
  1636.             (hardPTE & (VMMACH_REFERENCED_BIT | VMMACH_MODIFIED_BIT))) {
  1637.             refModMap[PhysToVirtPage(hardPTE & VMMACH_PAGE_FRAME_FIELD)]
  1638.              |= hardPTE & (VMMACH_REFERENCED_BIT | VMMACH_MODIFIED_BIT);
  1639.         }
  1640.         }
  1641.     }
  1642.     }
  1643.  
  1644.     /* Initialize the pmeg and delete it from the fifo.  If we aren't 
  1645.      * supposed to lock this pmeg, then put it at the rear of the list.
  1646.      */
  1647.     pmegPtr->segInfo.segPtr = softSegPtr;
  1648.     pmegPtr->segInfo.hardSegNum = hardSegNum;
  1649.     pmegPtr->pageCount = 0;
  1650.     List_Remove((List_Links *) pmegPtr);
  1651.     if (!(flags & PMEG_DONT_ALLOC)) {
  1652.     List_Insert((List_Links *) pmegPtr, LIST_ATREAR(pmegInuseList));
  1653.     }
  1654.     pmegPtr->flags = flags;
  1655.  
  1656.     return(pmegNum);
  1657. }
  1658.  
  1659.  
  1660. /*
  1661.  *----------------------------------------------------------------------
  1662.  *
  1663.  * GetNumValidPages --
  1664.  *
  1665.  *    Return the number of valid pages in a segment.
  1666.  *
  1667.  * Results:
  1668.  *    The number of valid pages.
  1669.  *
  1670.  * Side effects:
  1671.  *    None.
  1672.  *
  1673.  *----------------------------------------------------------------------
  1674.  */
  1675. static int
  1676. GetNumValidPages(virtAddr)
  1677.     Address    virtAddr;
  1678. {
  1679.     int        i;
  1680.     int        numValid = 0;
  1681.     unsigned    int    pte;
  1682.  
  1683.     for (i = 0; i < VMMACH_NUM_PAGES_PER_SEG_INT; i++) {
  1684.     pte = VmMachGetPageMap(virtAddr + (i * VMMACH_PAGE_SIZE_INT));
  1685.     if (pte & VMMACH_RESIDENT_BIT) {
  1686.         numValid++;
  1687.     }
  1688.     }
  1689.  
  1690.     return numValid;
  1691. }
  1692.  
  1693.  
  1694. /*
  1695.  *----------------------------------------------------------------------
  1696.  *
  1697.  * FlushValidPages --
  1698.  *
  1699.  *    Flush the valid pages in a segment.
  1700.  *
  1701.  * Results:
  1702.  *    None.
  1703.  *
  1704.  * Side effects:
  1705.  *    The valid pages in a segment are flushed.
  1706.  *
  1707.  *----------------------------------------------------------------------
  1708.  */
  1709. static void
  1710. FlushValidPages(virtAddr)
  1711.     Address    virtAddr;
  1712. {
  1713.     int        i;
  1714.     unsigned    int    pte;
  1715.  
  1716.     if (vmMachHasVACache) {
  1717.     for (i = 0; i < VMMACH_NUM_PAGES_PER_SEG_INT; i++) {
  1718.         pte = VmMachGetPageMap(virtAddr + (i * VMMACH_PAGE_SIZE_INT));
  1719.         if (pte & VMMACH_RESIDENT_BIT) {
  1720.         VmMachFlushPage(virtAddr + (i * VMMACH_PAGE_SIZE_INT));
  1721.         }
  1722.     }
  1723.     }
  1724. }
  1725.  
  1726.  
  1727. /*
  1728.  * ----------------------------------------------------------------------------
  1729.  *
  1730.  * PMEGFree --
  1731.  *
  1732.  *      Return the given pmeg to the pmeg list.
  1733.  *
  1734.  * Results:
  1735.  *      None.
  1736.  *
  1737.  * Side effects:
  1738.  *      The pmeg is returned to the pmeg list.
  1739.  *
  1740.  * ----------------------------------------------------------------------------
  1741.  */
  1742. INTERNAL static void
  1743. PMEGFree(pmegNum)
  1744.     int     pmegNum;    /* Which pmeg to free */
  1745. {
  1746.     register    PMEG    *pmegPtr;
  1747.     struct VmMach_PMEGseg    *segPtr, *nextPtr;
  1748.  
  1749.     pmegPtr = &pmegArray[pmegNum];
  1750.     /*
  1751.      * If this pmeg can never be freed then don't free it.  This case can
  1752.      * occur when a device is mapped into a user's address space.
  1753.      */
  1754.     if (pmegPtr->flags & PMEG_NEVER_FREE) {
  1755.     return;
  1756.     }
  1757.  
  1758.     if (pmegPtr->pageCount > 0) {
  1759.  
  1760.     /*
  1761.      * Deal with pages that are still cached in this pmeg.
  1762.      */
  1763.     VmMachPMEGZero(pmegNum);
  1764.     }
  1765.     if (pmegPtr->segInfo.segPtr != (Vm_Segment *)NIL) {
  1766.     for (segPtr = &pmegPtr->segInfo; segPtr != (struct VmMach_PMEGseg *)NIL;) {
  1767.         if (segPtr->segPtr->machPtr == (VmMach_SegData *)NIL) {
  1768.         printf("PMEGFree(%d): seg %d has no machPtr!\n", pmegNum,
  1769.             segPtr->segPtr->segNum);
  1770.         } else {
  1771.         *GetHardSegPtr(segPtr->segPtr->machPtr, segPtr->hardSegNum) =
  1772.             VMMACH_INV_PMEG;
  1773.         }
  1774.         nextPtr = segPtr->nextLink;
  1775.         if (segPtr != &pmegPtr->segInfo) {
  1776.         segPtr->inuse = 0;
  1777.         }
  1778.         segPtr = nextPtr;
  1779.     }
  1780.     }
  1781.     pmegPtr->segInfo.nextLink = (struct VmMach_PMEGseg *) NIL;
  1782.     pmegPtr->segInfo.segPtr = (Vm_Segment *) NIL;
  1783.  
  1784.     /*
  1785.      * I really don't understand the code here.  The original was the second
  1786.      * line.  The first line was to try to fix an error that shows up in
  1787.      * UnmapIntelPage(), but I've tried now to fix that error there, since the
  1788.      * second line breaks things elsewhere.
  1789.      */
  1790.     if (pmegPtr->pageCount == 0 || !(pmegPtr->flags & PMEG_DONT_ALLOC)) {
  1791.     List_Remove((List_Links *) pmegPtr);
  1792.     }
  1793.     pmegPtr->flags = 0;
  1794.     pmegPtr->lockCount = 0;
  1795.     /*
  1796.      * Put this pmeg at the front of the pmeg free list.
  1797.      */
  1798.     List_Insert((List_Links *) pmegPtr, LIST_ATFRONT(pmegFreeList));
  1799. }
  1800.  
  1801.  
  1802. /*
  1803.  * ----------------------------------------------------------------------------
  1804.  *
  1805.  * PMEGLock --
  1806.  *
  1807.  *      Increment the lock count on a pmeg.
  1808.  *
  1809.  * Results:
  1810.  *      TRUE if there was a valid PMEG behind the given hardware segment.
  1811.  *
  1812.  * Side effects:
  1813.  *      The lock count is incremented if there is a valid pmeg at the given
  1814.  *    hardware segment.
  1815.  *
  1816.  * ----------------------------------------------------------------------------
  1817.  */
  1818. ENTRY static Boolean
  1819. PMEGLock(machPtr, segNum)
  1820.     register VmMach_SegData    *machPtr;
  1821.     int                segNum;
  1822. {
  1823.     unsigned int pmegNum;
  1824.  
  1825.     MASTER_LOCK(vmMachMutexPtr);
  1826.  
  1827.     pmegNum = *GetHardSegPtr(machPtr, segNum);
  1828.     if (pmegNum != VMMACH_INV_PMEG) {
  1829.     pmegArray[pmegNum].lockCount++;
  1830.     MASTER_UNLOCK(vmMachMutexPtr);
  1831.     return(TRUE);
  1832.     } else {
  1833.     MASTER_UNLOCK(vmMachMutexPtr);
  1834.     return(FALSE);
  1835.     }
  1836. }
  1837.  
  1838.  
  1839. /*
  1840.  * ----------------------------------------------------------------------------
  1841.  *
  1842.  * VmMach_SetupContext --
  1843.  *
  1844.  *      Return the value of the context register for the given process.
  1845.  *    It is assumed that this routine is called on a uni-processor right
  1846.  *    before the process starts executing.
  1847.  *    
  1848.  * Results:
  1849.  *      None.
  1850.  *
  1851.  * Side effects:
  1852.  *      The context list is modified.
  1853.  *
  1854.  * ----------------------------------------------------------------------------
  1855.  */
  1856. ENTRY ClientData
  1857. VmMach_SetupContext(procPtr)
  1858.     register    Proc_ControlBlock    *procPtr;
  1859. {
  1860.     register    VmMach_Context    *contextPtr;
  1861.  
  1862.     MASTER_LOCK(vmMachMutexPtr);
  1863.  
  1864.     while (TRUE) {
  1865.     contextPtr = procPtr->vmPtr->machPtr->contextPtr;
  1866.     if (contextPtr != (VmMach_Context *)NIL) {
  1867.         if (contextPtr != &contextArray[VMMACH_KERN_CONTEXT]) {
  1868.         List_Move((List_Links *)contextPtr, LIST_ATREAR(contextList));
  1869.         }
  1870.         MASTER_UNLOCK(vmMachMutexPtr);
  1871.         return((ClientData)contextPtr->context);
  1872.     }
  1873.         SetupContext(procPtr);
  1874.     }
  1875. }
  1876.  
  1877.  
  1878. /*
  1879.  * ----------------------------------------------------------------------------
  1880.  *
  1881.  * SetupContext --
  1882.  *
  1883.  *      Initialize the context for the given process.  If the process does
  1884.  *    not have a context associated with it then one is allocated.
  1885.  *
  1886.  *    Note that this routine runs unsynchronized even though it is using
  1887.  *    internal structures.  See the note above while this is OK.  I
  1888.  *     eliminated the monitor lock because it is unnecessary anyway and
  1889.  *    it slows down context-switching.
  1890.  *    
  1891.  * Results:
  1892.  *      None.
  1893.  *
  1894.  * Side effects:
  1895.  *      The context field in the process table entry and the context list are
  1896.  *     both modified if a new context is allocated.
  1897.  *
  1898.  * ----------------------------------------------------------------------------
  1899.  */
  1900. INTERNAL static void
  1901. SetupContext(procPtr)
  1902.     register    Proc_ControlBlock    *procPtr;
  1903. {
  1904.     register    VmMach_Context    *contextPtr;
  1905.     register    VmMach_SegData    *segDataPtr;
  1906.     register    Vm_ProcInfo    *vmPtr;
  1907.     int        stolenContext    = FALSE;
  1908.  
  1909.     vmPtr = procPtr->vmPtr;
  1910.     contextPtr = vmPtr->machPtr->contextPtr;
  1911.  
  1912.     if (procPtr->genFlags & (PROC_KERNEL | PROC_NO_VM)) {
  1913.     /*
  1914.      * This is a kernel process or a process that is exiting.
  1915.      * Set the context to kernel and return.
  1916.      */
  1917.     VmMachSetContextReg(VMMACH_KERN_CONTEXT);
  1918.     vmPtr->machPtr->contextPtr = &contextArray[VMMACH_KERN_CONTEXT];
  1919.     return;
  1920.     }
  1921.  
  1922.     if (contextPtr == (VmMach_Context *)NIL) {
  1923.     /*
  1924.      * In this case there is no context setup for this process.  Therefore
  1925.      * we have to find a context, initialize the context table entry and 
  1926.      * initialize the context stuff in the proc table.
  1927.      */
  1928.     if (List_IsEmpty((List_Links *) contextList)) {
  1929.         panic("SetupContext: Context list empty\n");
  1930.     }
  1931.     /* 
  1932.      * Take the first context off of the context list.
  1933.      */
  1934.     contextPtr = (VmMach_Context *) List_First(contextList);
  1935.     if (contextPtr->flags & CONTEXT_IN_USE) {
  1936.         contextPtr->procPtr->vmPtr->machPtr->contextPtr =
  1937.                             (VmMach_Context *)NIL;
  1938.         vmStat.machDepStat.stealContext++;
  1939.         stolenContext = TRUE;
  1940.     }
  1941.     /*
  1942.      * Initialize the context table entry.
  1943.      */
  1944.     contextPtr->flags = CONTEXT_IN_USE;
  1945.     contextPtr->procPtr = procPtr;
  1946.     vmPtr->machPtr->contextPtr = contextPtr;
  1947.     VmMachSetContextReg((int)contextPtr->context);
  1948.     if (stolenContext && vmMachHasVACache) {
  1949.         VmMach_FlushCurrentContext();
  1950.     }
  1951.     /*
  1952.      * Set the context map.
  1953.      */
  1954.     {
  1955.         int            i;
  1956.         unsigned int    j;
  1957.  
  1958.         /*
  1959.          * Since user addresses are never higher than the bottom of the
  1960.          * hole in the address space, this will save something like 30ms
  1961.          * by ending at VMMACH_BOTTOM_OF_HOLE rather than mach_KernStart.
  1962.          */
  1963.         j = ((unsigned int)VMMACH_BOTTOM_OF_HOLE) >> VMMACH_SEG_SHIFT;
  1964.         for (i = 0; i < j; i++) {
  1965.         contextPtr->map[i] = VMMACH_INV_PMEG;
  1966.         }
  1967.     }
  1968.     segDataPtr = vmPtr->segPtrArray[VM_CODE]->machPtr;
  1969.     bcopy((Address)segDataPtr->segTablePtr, 
  1970.         (Address) (contextPtr->map + segDataPtr->offset),
  1971.         segDataPtr->numSegs * sizeof (VMMACH_SEG_NUM));
  1972.  
  1973.     segDataPtr = vmPtr->segPtrArray[VM_HEAP]->machPtr;
  1974.     bcopy((Address)segDataPtr->segTablePtr, 
  1975.         (Address) (contextPtr->map + segDataPtr->offset),
  1976.         segDataPtr->numSegs * sizeof (VMMACH_SEG_NUM));
  1977.  
  1978.     segDataPtr = vmPtr->segPtrArray[VM_STACK]->machPtr;
  1979.     bcopy((Address)segDataPtr->segTablePtr, 
  1980.         (Address) (contextPtr->map + segDataPtr->offset),
  1981.         segDataPtr->numSegs * sizeof (VMMACH_SEG_NUM));
  1982.     if (vmPtr->sharedSegs != (List_Links *)NIL) {
  1983.         Vm_SegProcList *segList;
  1984.         LIST_FORALL(vmPtr->sharedSegs,(List_Links *)segList) {
  1985.         segDataPtr = segList->segTabPtr->segPtr->machPtr;
  1986.         bcopy((Address)segDataPtr->segTablePtr, 
  1987.             (Address) (contextPtr->map+PageToSeg(segList->offset)),
  1988.             segDataPtr->numSegs);
  1989.         }
  1990.     }
  1991.     if (vmPtr->machPtr->mapSegPtr != (struct Vm_Segment *)NIL) {
  1992.         contextPtr->map[MAP_SEG_NUM] = vmPtr->machPtr->mapHardSeg;
  1993.     } else {
  1994.         contextPtr->map[MAP_SEG_NUM] = VMMACH_INV_PMEG;
  1995.     }
  1996.     /*
  1997.      * Push map out to hardware.
  1998.      */
  1999.     VmMachCopyUserSegMap(contextPtr->map);
  2000.     } else {
  2001.     VmMachSetContextReg((int)contextPtr->context);
  2002.     }
  2003.     List_Move((List_Links *)contextPtr, LIST_ATREAR(contextList));
  2004. }
  2005.  
  2006.  
  2007. /*
  2008.  * ----------------------------------------------------------------------------
  2009.  *
  2010.  * Vm_FreeContext --
  2011.  *
  2012.  *      Free the given context.
  2013.  *
  2014.  * Results:
  2015.  *      None.
  2016.  *
  2017.  * Side effects:
  2018.  *      The context table and context lists are modified.
  2019.  *
  2020.  * ----------------------------------------------------------------------------
  2021.  */
  2022. ENTRY void
  2023. VmMach_FreeContext(procPtr)
  2024.     register    Proc_ControlBlock    *procPtr;
  2025. {
  2026.     register    VmMach_Context    *contextPtr;
  2027.     register    VmMach_ProcData    *machPtr;
  2028.  
  2029.     MASTER_LOCK(vmMachMutexPtr);
  2030.  
  2031.     machPtr = procPtr->vmPtr->machPtr;
  2032.     contextPtr = machPtr->contextPtr;
  2033.     if (contextPtr == (VmMach_Context *)NIL ||
  2034.         contextPtr->context == VMMACH_KERN_CONTEXT) {
  2035.     MASTER_UNLOCK(vmMachMutexPtr);
  2036.     return;
  2037.     }
  2038.  
  2039.     List_Move((List_Links *)contextPtr, LIST_ATFRONT(contextList));
  2040.     contextPtr->flags = 0;
  2041.     machPtr->contextPtr = (VmMach_Context *)NIL;
  2042.  
  2043.     MASTER_UNLOCK(vmMachMutexPtr);
  2044. }
  2045.  
  2046.  
  2047. /*
  2048.  * ----------------------------------------------------------------------------
  2049.  *
  2050.  * VmMach_ReinitContext --
  2051.  *
  2052.  *      Free the current context and set up another one.  This is called
  2053.  *    by routines such as Proc_Exec that add things to the context and
  2054.  *    then have to abort or start a process running with a new image.
  2055.  *
  2056.  * Results:
  2057.  *      None.
  2058.  *
  2059.  * Side effects:
  2060.  *      The context table and context lists are modified.
  2061.  *
  2062.  * ----------------------------------------------------------------------------
  2063.  */
  2064. void
  2065. VmMach_ReinitContext(procPtr)
  2066.     register    Proc_ControlBlock    *procPtr;
  2067. {
  2068.     VmMach_FreeContext(procPtr);
  2069.     MASTER_LOCK(vmMachMutexPtr);
  2070.     procPtr->vmPtr->machPtr->contextPtr = (VmMach_Context *)NIL;
  2071.     SetupContext(procPtr);
  2072.     MASTER_UNLOCK(vmMachMutexPtr);
  2073. }
  2074.  
  2075. #if defined(sun2)
  2076.  
  2077. static int     allocatedPMEG;
  2078. static VmMachPTE intelSavedPTE;        /* The page table entry that is stored
  2079.                      * at the address that the intel page
  2080.                      * has to overwrite. */
  2081. static unsigned int intelPage;        /* The page frame that was allocated.*/
  2082. #endif
  2083.  
  2084.  
  2085. /*
  2086.  * ----------------------------------------------------------------------------
  2087.  *
  2088.  * VmMach_MapIntelPage --
  2089.  *
  2090.  *      Allocate and validate a page for the Intel Ethernet chip.  This routine
  2091.  *    is required in order to initialize the chip.  The chip expects 
  2092.  *    certain stuff to be at a specific virtual address when it is 
  2093.  *    initialized.  This routine sets things up so that the expected
  2094.  *    virtual address is accessible.
  2095.  *
  2096.  * Results:
  2097.  *      None.
  2098.  *
  2099.  * Side effects:
  2100.  *      The old pte stored at the virtual address and the page frame that is
  2101.  *    allocated are stored in static globals.
  2102.  *
  2103.  * ----------------------------------------------------------------------------
  2104.  */
  2105. #ifndef sun4c
  2106. /*ARGSUSED*/
  2107. void
  2108. VmMach_MapIntelPage(virtAddr) 
  2109.     Address    virtAddr; /* Virtual address where a page has to be validated
  2110.                  at. */
  2111. {
  2112. #if defined(sun2)
  2113.     VmMachPTE        pte;
  2114.     int            pmeg;
  2115.  
  2116.     /*
  2117.      * See if there is a PMEG already.  If not allocate one.
  2118.      */
  2119.     pmeg = VmMachGetSegMap(virtAddr);
  2120.     if (pmeg == VMMACH_INV_PMEG) {
  2121.     MASTER_LOCK(vmMachMutexPtr);
  2122.     /* No flush, since PMEGGet takes care of that. */
  2123.     allocatedPMEG = PMEGGet(vm_SysSegPtr, 
  2124.                 (unsigned)virtAddr >> VMMACH_SEG_SHIFT,
  2125.                 PMEG_DONT_ALLOC);
  2126.     MASTER_UNLOCK(vmMachMutexPtr);
  2127.     VmMachSetSegMap(virtAddr, allocatedPMEG);
  2128.     } else {
  2129.     allocatedPMEG = VMMACH_INV_PMEG;
  2130.     intelSavedPTE = VmMachGetPageMap(virtAddr);
  2131.     }
  2132.  
  2133.     /*
  2134.      * Set up the page table entry.
  2135.      */
  2136.     intelPage = Vm_KernPageAllocate();
  2137.     pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT | VirtToPhysPage(intelPage);
  2138.     /* No flush since this should never be cached. */
  2139.     SET_ALL_PAGE_MAP(virtAddr, pte);
  2140. #endif /* sun2  */
  2141. #ifdef sun4
  2142.     VmMachPTE        pte;
  2143.     int            pmeg;
  2144.     int            oldContext;
  2145.     int            i;
  2146.  
  2147.     /*
  2148.      * See if there is a PMEG already.  If not allocate one.
  2149.      */
  2150.     pmeg = VmMachGetSegMap(virtAddr);
  2151.     if (pmeg == VMMACH_INV_PMEG) {
  2152.     MASTER_LOCK(vmMachMutexPtr);
  2153.     /* No flush, since PMEGGet takes care of that. */
  2154.     pmeg = PMEGGet(vm_SysSegPtr, 
  2155.                 (int)((unsigned)virtAddr) >> VMMACH_SEG_SHIFT,
  2156.                 PMEG_DONT_ALLOC);
  2157.     MASTER_UNLOCK(vmMachMutexPtr);
  2158.     VmMachSetSegMap(virtAddr, pmeg);
  2159.     } 
  2160.     oldContext = VmMachGetContextReg();
  2161.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  2162.     VmMachSetContextReg(i);
  2163.     VmMachSetSegMap(virtAddr, pmeg);
  2164.     }
  2165.     VmMachSetContextReg(oldContext);
  2166.     /*
  2167.      * Set up the page table entry.
  2168.      */
  2169.     pte = VmMachGetPageMap(virtAddr);
  2170.     if (pte == 0) {
  2171.     pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT | VMMACH_DONT_CACHE_BIT |
  2172.           VirtToPhysPage(Vm_KernPageAllocate());
  2173.     SET_ALL_PAGE_MAP(virtAddr, pte);
  2174.     } 
  2175. #endif
  2176. }
  2177. #endif
  2178.  
  2179.  
  2180. /*
  2181.  * ----------------------------------------------------------------------------
  2182.  *
  2183.  * Vm_UnmapIntelPage --
  2184.  *
  2185.  *      Deallocate and invalidate a page for the intel chip.  This is a special
  2186.  *    case routine that is only for the intel ethernet chip.
  2187.  *
  2188.  * Results:
  2189.  *      None.
  2190.  *
  2191.  * Side effects:
  2192.  *      The hardware segment table associated with the segment
  2193.  *      is modified to invalidate the page.
  2194.  *
  2195.  * ----------------------------------------------------------------------------
  2196.  */
  2197. /*ARGSUSED*/
  2198. #ifndef sun4c
  2199. void
  2200. VmMach_UnmapIntelPage(virtAddr) 
  2201.     Address    virtAddr;
  2202. {
  2203. #if defined(sun2)
  2204.     PMEG        *pmegPtr;
  2205.     Boolean    found = FALSE;
  2206.  
  2207.     if (allocatedPMEG != VMMACH_INV_PMEG) {
  2208.     /*
  2209.      * Free up the PMEG.
  2210.      */
  2211.     /* No flush since this should never be cached. */
  2212.     VmMachSetPageMap(virtAddr, (VmMachPTE)0);
  2213.     VmMachSetSegMap(virtAddr, VMMACH_INV_PMEG);
  2214.  
  2215.     MASTER_LOCK(vmMachMutexPtr);
  2216.  
  2217.     /*
  2218.      * This is a little gross, but for some reason this pmeg has a 0
  2219.      * page count.  Since it has the PMEG_DONT_ALLOC flag set, it wasn't
  2220.      * removed from the pmegInuseList in PMEGGet().  So the remove done
  2221.      * in PMEGFree would remove it twice, unless we check.
  2222.      */
  2223.     LIST_FORALL(pmegInuseList, (List_Links *)pmegPtr) {
  2224.         if (pmegPtr == &pmegArray[allocatedPMEG]) {
  2225.         found = TRUE;
  2226.         }
  2227.     }
  2228.     if (!found) {
  2229.         pmegPtr = &pmegArray[allocatedPMEG];
  2230.         List_Insert((List_Links *) pmegPtr, LIST_ATREAR(pmegInuseList));
  2231.     }
  2232.     PMEGFree(allocatedPMEG);
  2233.  
  2234.     MASTER_UNLOCK(vmMachMutexPtr);
  2235.     } else {
  2236.     /*
  2237.      * Restore the saved pte and free the allocated page.
  2238.      */
  2239.     /* No flush since this should never be cached. */
  2240.     VmMachSetPageMap(virtAddr, intelSavedPTE);
  2241.     }
  2242.     Vm_KernPageFree(intelPage);
  2243. #endif
  2244. }
  2245. #endif /* sun4c */
  2246.  
  2247.  
  2248. static Address        netMemAddr;
  2249. static unsigned int    netLastPage;
  2250.  
  2251.  
  2252. /*
  2253.  * ----------------------------------------------------------------------------
  2254.  *
  2255.  * InitNetMem --
  2256.  *
  2257.  *      Initialize the memory mappings for the network.
  2258.  *
  2259.  * Results:
  2260.  *      None.
  2261.  *
  2262.  * Side effects:
  2263.  *      PMEGS are allocated and initialized.
  2264.  *
  2265.  * ----------------------------------------------------------------------------
  2266.  */
  2267. static void
  2268. InitNetMem()
  2269. {
  2270.     VMMACH_SEG_NUM        pmeg;
  2271.     register VMMACH_SEG_NUM    *segTablePtr;
  2272.     int                i;
  2273.     int                j;
  2274.     int                lastSegNum;
  2275.     int                segNum;
  2276.     Address            virtAddr;
  2277.  
  2278.     /*
  2279.      * Allocate pmegs  for net mapping.
  2280.      */
  2281.     segNum = ((unsigned)VMMACH_NET_MAP_START) >> VMMACH_SEG_SHIFT;
  2282.     lastSegNum = ((unsigned)(VMMACH_NET_MAP_START+VMMACH_NET_MAP_SIZE-1)) /
  2283.               VMMACH_SEG_SIZE;
  2284.  
  2285.     for (i = 0, virtAddr = (Address)VMMACH_NET_MAP_START,
  2286.         segTablePtr = GetHardSegPtr(vm_SysSegPtr->machPtr, segNum);
  2287.      segNum <= lastSegNum;
  2288.          i++, virtAddr += VMMACH_SEG_SIZE, segNum++) {
  2289.     pmeg = VmMachGetSegMap(virtAddr);
  2290.     if (pmeg == VMMACH_INV_PMEG) {
  2291.         *(segTablePtr + i) = PMEGGet(vm_SysSegPtr, segNum, PMEG_DONT_ALLOC);
  2292.         VmMachSetSegMap(virtAddr, (int)*(segTablePtr + i));
  2293.     } else {
  2294.         *(segTablePtr + i) = pmeg;
  2295.     }
  2296.     /*
  2297.      * Propagate the new pmeg mapping to all contexts.
  2298.      */
  2299.     for (j = 0; j < VMMACH_NUM_CONTEXTS; j++) {
  2300.         if (j == VMMACH_KERN_CONTEXT) {
  2301.         continue;
  2302.         }
  2303.         VmMachSetContextReg(j);
  2304.         VmMachSetSegMap(virtAddr, (int)*(segTablePtr + i));
  2305.     }
  2306.     VmMachSetContextReg(VMMACH_KERN_CONTEXT);
  2307.     }
  2308.     /*
  2309.      * Repeat for the network memory range. 
  2310.      */
  2311.     segNum = ((unsigned)VMMACH_NET_MEM_START) >> VMMACH_SEG_SHIFT;
  2312.     lastSegNum = ((unsigned)(VMMACH_NET_MEM_START+VMMACH_NET_MEM_SIZE-1)) /
  2313.              VMMACH_SEG_SIZE;
  2314.  
  2315.     for (i = 0, virtAddr = (Address)VMMACH_NET_MEM_START,
  2316.         segTablePtr = GetHardSegPtr(vm_SysSegPtr->machPtr, segNum);
  2317.      segNum <= lastSegNum;
  2318.          i++, virtAddr += VMMACH_SEG_SIZE, segNum++) {
  2319.     pmeg = VmMachGetSegMap(virtAddr);
  2320.     if (pmeg == VMMACH_INV_PMEG) {
  2321.         *(segTablePtr + i) = PMEGGet(vm_SysSegPtr, segNum, PMEG_DONT_ALLOC);
  2322.         VmMachSetSegMap(virtAddr, (int)*(segTablePtr + i));
  2323.     } else {
  2324.         *(segTablePtr + i) = pmeg;
  2325.     }
  2326.     /*
  2327.      * Propagate the new pmeg mapping to all contexts.
  2328.      */
  2329.     for (j = 0; j < VMMACH_NUM_CONTEXTS; j++) {
  2330.         if (j == VMMACH_KERN_CONTEXT) {
  2331.         continue;
  2332.         }
  2333.         VmMachSetContextReg(j);
  2334.         VmMachSetSegMap(virtAddr, (int)*(segTablePtr + i));
  2335.     }
  2336.     VmMachSetContextReg(VMMACH_KERN_CONTEXT);
  2337.     }
  2338.  
  2339.     netMemAddr = (Address)VMMACH_NET_MEM_START;
  2340.     netLastPage = (((unsigned)VMMACH_NET_MEM_START) >> VMMACH_PAGE_SHIFT) - 1;
  2341. }
  2342.  
  2343. /*
  2344.  * ----------------------------------------------------------------------------
  2345.  *
  2346.  * VmMach_NetMemAlloc --
  2347.  *
  2348.  *      Allocate physical memory for a network driver.
  2349.  *
  2350.  * Results:
  2351.  *      The address where the memory is allocated at.
  2352.  *
  2353.  * Side effects:
  2354.  *      Memory allocated.
  2355.  *
  2356.  * ----------------------------------------------------------------------------
  2357.  */
  2358. Address
  2359. VmMach_NetMemAlloc(numBytes)
  2360.     int    numBytes;    /* Number of bytes of memory to allocated. */
  2361. {
  2362.     VmMachPTE    pte;
  2363.     Address    retAddr;
  2364.     Address    maxAddr;
  2365.     Address    virtAddr;
  2366.     static Boolean initialized = FALSE;
  2367.  
  2368.     if (!initialized) {
  2369.     InitNetMem();
  2370.     initialized = TRUE;
  2371.     }
  2372.  
  2373.     retAddr = netMemAddr;
  2374.     netMemAddr += (numBytes + 7) & ~7;    /* is this necessary for sun4? */
  2375.     /*
  2376.      * Panic if we are out of memory.  
  2377.      */
  2378.     if (netMemAddr > (Address) (VMMACH_NET_MEM_START + VMMACH_NET_MEM_SIZE)) {
  2379.     panic("VmMach_NetMemAlloc: Out of network memory\n");
  2380.     }
  2381.  
  2382.     maxAddr = (Address) ((netLastPage + 1) * VMMACH_PAGE_SIZE - 1);
  2383.  
  2384.     /*
  2385.      * Add new pages to the virtual address space until we have added enough
  2386.      * to handle this memory request.
  2387.      */
  2388.     while (netMemAddr - 1 > maxAddr) {
  2389.     maxAddr += VMMACH_PAGE_SIZE;
  2390.     netLastPage++;
  2391.     virtAddr = (Address) (netLastPage << VMMACH_PAGE_SHIFT);
  2392.     pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT |
  2393. #ifdef sun4c
  2394.           /*
  2395.            * For some reason on the sparcStation, we can't allow the
  2396.            * network pages to be cached. This is really a problem and it
  2397.            * totally breaks the driver.
  2398.            */
  2399.           VMMACH_DONT_CACHE_BIT | 
  2400. #endif
  2401.           VirtToPhysPage(Vm_KernPageAllocate());
  2402.     SET_ALL_PAGE_MAP(virtAddr, pte);
  2403.     }
  2404.  
  2405.     bzero(retAddr, numBytes);
  2406.     return(retAddr);
  2407. }
  2408.  
  2409.  
  2410. /*
  2411.  *----------------------------------------------------------------------
  2412.  *
  2413.  * VmMach_NetMapPacket --
  2414.  *
  2415.  *    Map the packet pointed to by the scatter-gather array.
  2416.  *
  2417.  * Results:
  2418.  *    None.
  2419.  *
  2420.  * Side effects:
  2421.  *    The outScatGathArray is filled in with pointers to where the
  2422.  *    packet was mapped in.
  2423.  *
  2424.  *----------------------------------------------------------------------
  2425.  */
  2426. void
  2427. VmMach_NetMapPacket(inScatGathPtr, scatGathLength, outScatGathPtr)
  2428.     register Net_ScatterGather    *inScatGathPtr;
  2429.     register int        scatGathLength;
  2430.     register Net_ScatterGather    *outScatGathPtr;
  2431. {
  2432.     register Address    mapAddr;
  2433.     register Address    endAddr;
  2434. #ifndef sun4c
  2435.     int            segNum;
  2436.     int            pageNum = 0;
  2437. #endif
  2438.  
  2439. #ifdef sun4c
  2440.     /*
  2441.      * The network driver on the sparcstation never accesses the data
  2442.      * through the cache, so there should be no need to flush it.
  2443.      */
  2444.     for (mapAddr = (Address)VMMACH_NET_MAP_START;
  2445.         scatGathLength > 0;
  2446.         scatGathLength--, inScatGathPtr++, outScatGathPtr++) {
  2447.         outScatGathPtr->length = inScatGathPtr->length;
  2448.         if (inScatGathPtr->length == 0) {
  2449.             continue;
  2450.         }
  2451.         /*
  2452.          * Map the piece of the packet in.  Note that we know that a packet
  2453.          * piece is no longer than 1536 bytes so we know that we will need
  2454.          * at most two page table entries to map a piece in.
  2455.          */
  2456.         VmMachSetPageMap(mapAddr, VmMachGetPageMap(inScatGathPtr->bufAddr));
  2457.         outScatGathPtr->bufAddr = mapAddr +
  2458.         ((unsigned)inScatGathPtr->bufAddr & VMMACH_OFFSET_MASK_INT);
  2459.         mapAddr += VMMACH_PAGE_SIZE_INT;
  2460.         endAddr = inScatGathPtr->bufAddr + inScatGathPtr->length - 1;
  2461.         if (((unsigned)inScatGathPtr->bufAddr & ~VMMACH_OFFSET_MASK_INT) !=
  2462.             ((unsigned)endAddr & ~VMMACH_OFFSET_MASK_INT)) {
  2463.             VmMachSetPageMap(mapAddr, VmMachGetPageMap(endAddr));
  2464.             mapAddr += VMMACH_PAGE_SIZE_INT;
  2465.         }
  2466.     }
  2467. #else
  2468.     for (segNum = 0 ; scatGathLength > 0;
  2469.         scatGathLength--, inScatGathPtr++, outScatGathPtr++) {
  2470.     outScatGathPtr->length = inScatGathPtr->length;
  2471.     if (inScatGathPtr->length == 0) {
  2472.         continue;
  2473.     }
  2474.     /*
  2475.      * For the first (VMMACH_NUM_NET_SEGS) - 1 elements in the
  2476.      * scatter gather array, map each element into a segment, aligned
  2477.      * with the mapping pages so that cache flushes will be avoided.
  2478.      */
  2479.     if (segNum < VMMACH_NUM_NET_SEGS - 1) {
  2480.         /* do silly mapping */
  2481.         mapAddr = (Address)VMMACH_NET_MAP_START +
  2482.             (segNum * VMMACH_SEG_SIZE);
  2483.         /* align to same cache boundary */
  2484.         mapAddr += ((unsigned int)inScatGathPtr->bufAddr &
  2485.             (VMMACH_CACHE_SIZE - 1));
  2486.         /* set addr to beginning of page */
  2487.         mapAddr = (Address)((unsigned int) mapAddr & ~VMMACH_OFFSET_MASK);
  2488.         if (vmMachHasVACache) {
  2489.         VmMachFlushPage(mapAddr);
  2490.         }
  2491.         VmMachSetPageMap(mapAddr, VmMachGetPageMap(inScatGathPtr->bufAddr));
  2492.         outScatGathPtr->bufAddr = (Address) ((unsigned)mapAddr +
  2493.             ((unsigned)inScatGathPtr->bufAddr & VMMACH_OFFSET_MASK));
  2494.         mapAddr += VMMACH_PAGE_SIZE_INT;
  2495.         endAddr = (Address)inScatGathPtr->bufAddr +
  2496.             inScatGathPtr->length - 1;
  2497.         if (((unsigned)inScatGathPtr->bufAddr & ~VMMACH_OFFSET_MASK_INT) !=
  2498.         ((unsigned)endAddr & ~VMMACH_OFFSET_MASK_INT)) {
  2499.         if (vmMachHasVACache) {
  2500.             VmMachFlushPage(mapAddr);
  2501.         }
  2502.         VmMachSetPageMap(mapAddr, VmMachGetPageMap(endAddr));
  2503.         }
  2504.         segNum++;
  2505.     } else {
  2506.         /*
  2507.          * For elements beyond the last one, map them all into the
  2508.          * last mapping segment.  Cache flushing will be necessary for
  2509.          * these.
  2510.          */
  2511.         mapAddr = (Address)VMMACH_NET_MAP_START +
  2512.             (segNum * VMMACH_SEG_SIZE) + (pageNum * VMMACH_PAGE_SIZE);
  2513.         if (vmMachHasVACache) {
  2514.         VmMachFlushPage(inScatGathPtr->bufAddr);
  2515.         VmMachFlushPage(mapAddr);
  2516.         }
  2517.         VmMachSetPageMap(mapAddr, VmMachGetPageMap(inScatGathPtr->bufAddr));
  2518.         outScatGathPtr->bufAddr = (Address) ((unsigned)mapAddr +
  2519.             ((unsigned)inScatGathPtr->bufAddr & VMMACH_OFFSET_MASK));
  2520.         mapAddr += VMMACH_PAGE_SIZE_INT;
  2521.         pageNum++;
  2522.         endAddr = (Address)inScatGathPtr->bufAddr +
  2523.             inScatGathPtr->length - 1;
  2524.         if (((unsigned)inScatGathPtr->bufAddr & ~VMMACH_OFFSET_MASK_INT) !=
  2525.         ((unsigned)endAddr & ~VMMACH_OFFSET_MASK_INT)) {
  2526.         if (vmMachHasVACache) {
  2527.             VmMachFlushPage(endAddr);
  2528.             VmMachFlushPage(mapAddr);
  2529.         }
  2530.         VmMachSetPageMap(mapAddr, VmMachGetPageMap(endAddr));
  2531.         pageNum++;
  2532.         }
  2533.         printf("MapPacket: segNum is %d, pageNum is %d\n", segNum, pageNum);
  2534.     }
  2535.     }
  2536. #endif /* sun4c */
  2537. }
  2538.  
  2539.  
  2540.  
  2541. /*
  2542.  *----------------------------------------------------------------------
  2543.  *
  2544.  * VmMach_VirtAddrParse --
  2545.  *
  2546.  *    See if the given address falls into the special mapping segment.
  2547.  *    If so parse it for our caller.
  2548.  *
  2549.  * Results:
  2550.  *    TRUE if the address fell into the special mapping segment, FALSE
  2551.  *    otherwise.
  2552.  *
  2553.  * Side effects:
  2554.  *    *transVirtAddrPtr may be filled in.
  2555.  *
  2556.  *----------------------------------------------------------------------
  2557.  */
  2558. Boolean
  2559. VmMach_VirtAddrParse(procPtr, virtAddr, transVirtAddrPtr)
  2560.     Proc_ControlBlock        *procPtr;
  2561.     Address            virtAddr;
  2562.     register    Vm_VirtAddr    *transVirtAddrPtr;
  2563. {
  2564.     Address    origVirtAddr;
  2565.     Boolean    retVal;
  2566.  
  2567. #ifdef sun4
  2568.     if (!VMMACH_ADDR_CHECK(virtAddr)) {
  2569.     panic("VmMach_VirtAddrParse: virt addr 0x%x falls in illegal range!\n",
  2570.         virtAddr);
  2571.     }
  2572. #endif sun4
  2573.     if (virtAddr >= (Address)VMMACH_MAP_SEG_ADDR && 
  2574.         virtAddr < (Address)mach_KernStart) {
  2575.     /*
  2576.      * The address falls into the special mapping segment.  Translate
  2577.      * the address back to the segment that it falls into.
  2578.      */
  2579.     transVirtAddrPtr->segPtr = procPtr->vmPtr->machPtr->mapSegPtr;
  2580.     origVirtAddr = 
  2581.         (Address)(procPtr->vmPtr->machPtr->mapHardSeg << VMMACH_SEG_SHIFT);
  2582.     transVirtAddrPtr->sharedPtr = procPtr->vmPtr->machPtr->sharedPtr;
  2583.      if (transVirtAddrPtr->segPtr->type == VM_SHARED) {
  2584.          origVirtAddr -= ( transVirtAddrPtr->segPtr->offset
  2585.              >>(VMMACH_SEG_SHIFT-VMMACH_PAGE_SHIFT))
  2586.              << VMMACH_SEG_SHIFT;
  2587.         origVirtAddr += segOffset(transVirtAddrPtr)<<VMMACH_PAGE_SHIFT;
  2588.      }
  2589.     origVirtAddr += (unsigned int)virtAddr & (VMMACH_SEG_SIZE - 1);
  2590.     transVirtAddrPtr->page = (unsigned) (origVirtAddr) >> VMMACH_PAGE_SHIFT;
  2591.     transVirtAddrPtr->offset = (unsigned)virtAddr & VMMACH_OFFSET_MASK;
  2592.     transVirtAddrPtr->flags = USING_MAPPED_SEG;
  2593.     retVal = TRUE;
  2594.     } else {
  2595.     retVal = FALSE;
  2596.     }
  2597.     return(retVal);
  2598. }
  2599.  
  2600.  
  2601.  
  2602. /*
  2603.  *----------------------------------------------------------------------
  2604.  *
  2605.  * VmMach_CopyInProc --
  2606.  *
  2607.  *    Copy from another process's address space into the current address
  2608.  *    space.   This is done by mapping the other processes segment into
  2609.  *    the current VAS and then doing the copy.  It assumed that this 
  2610.  *    routine is called with the source process locked such that its
  2611.  *    VM will not go away while we are doing this copy.
  2612.  *
  2613.  * Results:
  2614.  *    SUCCESS if the copy succeeded, SYS_ARG_NOACCESS if fromAddr is invalid.
  2615.  *
  2616.  * Side effects:
  2617.  *    What toAddr points to is modified.
  2618.  *
  2619.  *----------------------------------------------------------------------
  2620.  */
  2621. /*ARGSUSED*/
  2622. ReturnStatus
  2623. VmMach_CopyInProc(numBytes, fromProcPtr, fromAddr, virtAddrPtr,
  2624.           toAddr, toKernel)
  2625.     int     numBytes;        /* The maximum number of bytes to 
  2626.                        copy in. */
  2627.     Proc_ControlBlock    *fromProcPtr;    /* Which process to copy from.*/
  2628.     Address        fromAddr;    /* The address to copy from */
  2629.     Vm_VirtAddr        *virtAddrPtr;
  2630.     Address        toAddr;        /* The address to copy to */
  2631.     Boolean        toKernel;    /* This copy is happening to the
  2632.                      * kernel's address space. */
  2633. {
  2634.     ReturnStatus        status = SUCCESS;
  2635.     register VmMach_ProcData    *machPtr;
  2636.     Proc_ControlBlock        *toProcPtr;
  2637.     int                segOffset;
  2638.     int                bytesToCopy;
  2639.     int                oldContext;
  2640.  
  2641.     toProcPtr = Proc_GetCurrentProc();
  2642.     machPtr = toProcPtr->vmPtr->machPtr;
  2643.     machPtr->mapSegPtr = virtAddrPtr->segPtr;
  2644.     machPtr->mapHardSeg = (unsigned int) (fromAddr) >> VMMACH_SEG_SHIFT;
  2645.     machPtr->sharedPtr = virtAddrPtr->sharedPtr;
  2646.     if (virtAddrPtr->sharedPtr != (Vm_SegProcList*)NIL) {
  2647.     /*
  2648.      * Mangle the segment offset so that it matches the offset
  2649.      * of the mapped segment.
  2650.      */
  2651.     if (debugVmStubs) {
  2652.         printf("Copying in shared segment\n");
  2653.     }
  2654.     machPtr->mapHardSeg -= (virtAddrPtr->sharedPtr->offset<<
  2655.         VMMACH_PAGE_SHIFT_INT)>>VMMACH_SEG_SHIFT;
  2656.     machPtr->mapHardSeg += machPtr->mapSegPtr->machPtr->offset;
  2657.     }
  2658.  
  2659. #ifdef sun4
  2660.     /*
  2661.      * Since this is a cross-address-space copy, we must make sure everything
  2662.      * has been flushed to the stack from our windows so that we don't
  2663.      * miss stuff on the stack not yet flushed. 
  2664.      */
  2665.     Mach_FlushWindowsToStack();
  2666. #endif
  2667.  
  2668.     /*
  2669.      * Do a hardware segment's worth at a time until done.
  2670.      */
  2671.     while (numBytes > 0 && status == SUCCESS) {
  2672.     segOffset = (unsigned int)fromAddr & (VMMACH_SEG_SIZE - 1);
  2673.     bytesToCopy = VMMACH_SEG_SIZE - segOffset;
  2674.     if (bytesToCopy > numBytes) {
  2675.         bytesToCopy = numBytes;
  2676.     }
  2677.     /*
  2678.      * First try quick and dirty copy.  If it fails, do regular copy.
  2679.      */
  2680.     if (fromProcPtr->vmPtr->machPtr->contextPtr != (VmMach_Context *)NIL) {
  2681.         unsigned int    fromContext;
  2682.         unsigned int    toContext;
  2683.  
  2684.         toContext = VmMachGetContextReg();
  2685.         fromContext = fromProcPtr->vmPtr->machPtr->contextPtr->context;
  2686.  
  2687.         status = VmMachQuickNDirtyCopy(bytesToCopy, fromAddr, toAddr,
  2688.         fromContext, toContext);
  2689.         VmMachSetContextReg((int)toContext);
  2690.  
  2691.         if (status == SUCCESS) {
  2692.         numBytes -= bytesToCopy;
  2693.         fromAddr += bytesToCopy;
  2694.         toAddr += bytesToCopy;
  2695.         continue;
  2696.         }
  2697.     }
  2698.     /*
  2699.      * Flush segment in context of fromProcPtr.  If the context is NIL, then
  2700.      * we can't and don't have to flush it, since it will be flushed
  2701.      * before being reused.
  2702.      */
  2703.     if (vmMachHasVACache &&
  2704.         fromProcPtr->vmPtr->machPtr->contextPtr != (VmMach_Context *)NIL) {
  2705.  
  2706.         oldContext = VmMachGetContextReg();
  2707.         VmMachSetContextReg(
  2708.             (int)fromProcPtr->vmPtr->machPtr->contextPtr->context);
  2709.         VmMachFlushSegment(fromAddr);
  2710.         VmMachSetContextReg(oldContext);
  2711.     }
  2712.     /*
  2713.      * Push out the hardware segment.
  2714.      */
  2715.     WriteHardMapSeg(machPtr);
  2716.     /*
  2717.      * Do the copy.
  2718.      */
  2719.     toProcPtr->vmPtr->vmFlags |= VM_COPY_IN_PROGRESS;
  2720.     status = VmMachDoCopy(bytesToCopy,
  2721.                   (Address)(VMMACH_MAP_SEG_ADDR + segOffset),
  2722.                   toAddr);
  2723.     toProcPtr->vmPtr->vmFlags &= ~VM_COPY_IN_PROGRESS;
  2724.     if (status == SUCCESS) {
  2725.         numBytes -= bytesToCopy;
  2726.         fromAddr += bytesToCopy;
  2727.         toAddr += bytesToCopy;
  2728.     } else {
  2729.         status = SYS_ARG_NOACCESS;
  2730.     }
  2731.     /*
  2732.      * Zap the hardware segment.
  2733.      */
  2734.     if (vmMachHasVACache) {
  2735.         VmMachFlushSegment((Address) VMMACH_MAP_SEG_ADDR);
  2736.     }
  2737.     VmMachSetSegMap((Address)VMMACH_MAP_SEG_ADDR, VMMACH_INV_PMEG); 
  2738.     machPtr->mapHardSeg++;
  2739.     }
  2740.     machPtr->mapSegPtr = (struct Vm_Segment *)NIL;
  2741.     return(status);
  2742. }
  2743.  
  2744.  
  2745. /*
  2746.  *----------------------------------------------------------------------
  2747.  *
  2748.  * VmMach_CopyOutProc --
  2749.  *
  2750.  *    Copy from the current VAS to another processes VAS.  This is done by 
  2751.  *    mapping the other processes segment into the current VAS and then 
  2752.  *    doing the copy.  It assumed that this routine is called with the dest
  2753.  *    process locked such that its VM will not go away while we are doing
  2754.  *    the copy.
  2755.  *
  2756.  * Results:
  2757.  *    SUCCESS if the copy succeeded, SYS_ARG_NOACCESS if fromAddr is invalid.
  2758.  *
  2759.  * Side effects:
  2760.  *    What toAddr points to is modified.
  2761.  *
  2762.  *----------------------------------------------------------------------
  2763.  */
  2764. /*ARGSUSED*/
  2765. ReturnStatus
  2766. VmMach_CopyOutProc(numBytes, fromAddr, fromKernel, toProcPtr, toAddr,
  2767.            virtAddrPtr)
  2768.     int         numBytes;    /* The maximum number of bytes to 
  2769.                        copy in. */
  2770.     Address        fromAddr;    /* The address to copy from */
  2771.     Boolean        fromKernel;    /* This copy is happening to the
  2772.                      * kernel's address space. */
  2773.     Proc_ControlBlock    *toProcPtr;    /* Which process to copy from.*/
  2774.     Address        toAddr;        /* The address to copy to */
  2775.     Vm_VirtAddr        *virtAddrPtr;
  2776. {
  2777.     ReturnStatus        status = SUCCESS;
  2778.     register VmMach_ProcData    *machPtr;
  2779.     Proc_ControlBlock        *fromProcPtr;
  2780.     int                segOffset;
  2781.     int                bytesToCopy;
  2782.     int                oldContext;
  2783.  
  2784.  
  2785.     fromProcPtr = Proc_GetCurrentProc();
  2786.     machPtr = fromProcPtr->vmPtr->machPtr;
  2787.     machPtr->mapSegPtr = virtAddrPtr->segPtr;
  2788.     machPtr->mapHardSeg = (unsigned int) (toAddr) >> VMMACH_SEG_SHIFT;
  2789.     machPtr->sharedPtr = virtAddrPtr->sharedPtr;
  2790.     if (virtAddrPtr->sharedPtr != (Vm_SegProcList*)NIL) {
  2791.     /*
  2792.      * Mangle the segment offset so that it matches the offset
  2793.      * of the mapped segment.
  2794.      */
  2795.     if (debugVmStubs) {
  2796.         printf("Copying out shared segment\n");
  2797.     }
  2798.     machPtr->mapHardSeg -= (virtAddrPtr->sharedPtr->offset<<
  2799.         VMMACH_PAGE_SHIFT_INT)>>VMMACH_SEG_SHIFT;
  2800.     machPtr->mapHardSeg += machPtr->mapSegPtr->machPtr->offset;
  2801.     }
  2802.  
  2803. #ifdef sun4
  2804.     /*
  2805.      * Since this is a cross-address-space copy, we must make sure everything
  2806.      * has been flushed to the stack from our windows so that we don't
  2807.      * get stuff from windows overwriting stuff we copy to the stack later
  2808.      * when they're flushed.
  2809.      */
  2810.     Mach_FlushWindowsToStack();
  2811. #endif
  2812.  
  2813.     /*
  2814.      * Do a hardware segment's worth at a time until done.
  2815.      */
  2816.     while (numBytes > 0 && status == SUCCESS) {
  2817.     segOffset = (unsigned int)toAddr & (VMMACH_SEG_SIZE - 1);
  2818.     bytesToCopy = VMMACH_SEG_SIZE - segOffset;
  2819.     if (bytesToCopy > numBytes) {
  2820.         bytesToCopy = numBytes;
  2821.     }
  2822.     /*
  2823.      * First try quick and dirty copy.  If it fails, do regular copy.
  2824.      */
  2825.     if (toProcPtr->vmPtr->machPtr->contextPtr != (VmMach_Context *)NIL) {
  2826.         unsigned int    fromContext;
  2827.         unsigned int    toContext;
  2828.  
  2829.         fromContext = VmMachGetContextReg();
  2830.         toContext = toProcPtr->vmPtr->machPtr->contextPtr->context;
  2831.  
  2832.         status = VmMachQuickNDirtyCopy(bytesToCopy, fromAddr, toAddr,
  2833.             fromContext, toContext);
  2834.         VmMachSetContextReg((int)fromContext);
  2835.  
  2836.         if (status == SUCCESS) {
  2837.         numBytes -= bytesToCopy;
  2838.         fromAddr += bytesToCopy;
  2839.         toAddr += bytesToCopy;
  2840.         continue;
  2841.         }
  2842.     }
  2843.     /*
  2844.      * Flush segment in context of toProcPtr.  If the context is NIL, then
  2845.      * we can't and don't have to flush it, since it will be flushed before
  2846.      * being re-used.
  2847.      */
  2848.     if (vmMachHasVACache &&
  2849.         toProcPtr->vmPtr->machPtr->contextPtr != (VmMach_Context *)NIL) {
  2850.  
  2851.         oldContext = VmMachGetContextReg();
  2852.         VmMachSetContextReg(
  2853.             (int)toProcPtr->vmPtr->machPtr->contextPtr->context);
  2854.         VmMachFlushSegment(toAddr);
  2855.         VmMachSetContextReg(oldContext);
  2856.     }
  2857.     /*
  2858.      * Push out the hardware segment.
  2859.      */
  2860.     WriteHardMapSeg(machPtr);
  2861.     /*
  2862.      * Do the copy.
  2863.      */
  2864.     fromProcPtr->vmPtr->vmFlags |= VM_COPY_IN_PROGRESS;
  2865.     status = VmMachDoCopy(bytesToCopy, fromAddr,
  2866.               (Address) (VMMACH_MAP_SEG_ADDR + segOffset));
  2867.     fromProcPtr->vmPtr->vmFlags &= ~VM_COPY_IN_PROGRESS;
  2868.     if (status == SUCCESS) {
  2869.         numBytes -= bytesToCopy;
  2870.         fromAddr += bytesToCopy;
  2871.         toAddr += bytesToCopy;
  2872.     } else {
  2873.         status = SYS_ARG_NOACCESS;
  2874.     }
  2875.     /*
  2876.      * Zap the hardware segment.
  2877.      */
  2878.  
  2879.     /* Flush this in current context */
  2880.     if (vmMachHasVACache) {
  2881.         VmMachFlushSegment((Address) VMMACH_MAP_SEG_ADDR);
  2882.     }
  2883.     VmMachSetSegMap((Address)VMMACH_MAP_SEG_ADDR, VMMACH_INV_PMEG); 
  2884.  
  2885.     machPtr->mapHardSeg++;
  2886.     }
  2887.     machPtr->mapSegPtr = (struct Vm_Segment *)NIL;
  2888.     return(status);
  2889. }
  2890.  
  2891.  
  2892. /*
  2893.  *----------------------------------------------------------------------
  2894.  *
  2895.  * WriteHardMapSeg --
  2896.  *
  2897.  *    Push the hardware segment map entry out to the hardware for the
  2898.  *    given mapped segment.
  2899.  *
  2900.  * Results:
  2901.  *    None.
  2902.  *
  2903.  * Side effects:
  2904.  *    Hardware segment modified.
  2905.  *
  2906.  *----------------------------------------------------------------------
  2907.  */
  2908. ENTRY static void
  2909. WriteHardMapSeg(machPtr)
  2910.     VmMach_ProcData    *machPtr;
  2911. {
  2912.     MASTER_LOCK(vmMachMutexPtr);
  2913.  
  2914.     if (machPtr->contextPtr != (VmMach_Context *) NIL) {
  2915.     machPtr->contextPtr->map[MAP_SEG_NUM] = 
  2916.         (int)*GetHardSegPtr(machPtr->mapSegPtr->machPtr,
  2917.         machPtr->mapHardSeg);
  2918.     }
  2919.     VmMachSetSegMap((Address)VMMACH_MAP_SEG_ADDR, 
  2920.      (int)*GetHardSegPtr(machPtr->mapSegPtr->machPtr, machPtr->mapHardSeg));
  2921.  
  2922.     MASTER_UNLOCK(vmMachMutexPtr);
  2923. }
  2924.  
  2925.  
  2926. /*
  2927.  *----------------------------------------------------------------------
  2928.  *
  2929.  * VmMach_SetSegProt --
  2930.  *
  2931.  *    Change the protection in the page table for the given range of bytes
  2932.  *    for the given segment.
  2933.  *
  2934.  * Results:
  2935.  *    None.
  2936.  *
  2937.  * Side effects:
  2938.  *    Page table may be modified for the segment.
  2939.  *
  2940.  *----------------------------------------------------------------------
  2941.  */
  2942. ENTRY void
  2943. VmMach_SetSegProt(segPtr, firstPage, lastPage, makeWriteable)
  2944.     register Vm_Segment        *segPtr;    /* Segment to change protection
  2945.                            for. */
  2946.     register int        firstPage;  /* First page to set protection
  2947.                          * for. */
  2948.     int                lastPage;   /* First page to set protection
  2949.                          * for. */
  2950.     Boolean            makeWriteable;/* TRUE => make the pages 
  2951.                            *     writable.
  2952.                            * FALSE => make readable only.*/
  2953. {
  2954.     register    VmMachPTE    pte;
  2955.     register    Address        virtAddr;
  2956.     register    VMMACH_SEG_NUM    *pmegNumPtr;
  2957.     register    PMEG        *pmegPtr;
  2958.     register    Boolean        skipSeg = FALSE;
  2959.     Boolean            nextSeg = TRUE;
  2960.     Address            tVirtAddr;
  2961.     Address            pageVirtAddr;
  2962.     int                i;
  2963.     int                oldContext;
  2964.  
  2965.     MASTER_LOCK(vmMachMutexPtr);
  2966.  
  2967.     pmegNumPtr = (VMMACH_SEG_NUM *)
  2968.         GetHardSegPtr(segPtr->machPtr, PageToSeg(firstPage)) - 1;
  2969.     virtAddr = (Address)(firstPage << VMMACH_PAGE_SHIFT);
  2970.     while (firstPage <= lastPage) {
  2971.     if (nextSeg) {
  2972.         pmegNumPtr++;
  2973.         if (*pmegNumPtr != VMMACH_INV_PMEG) {
  2974.         pmegPtr = &pmegArray[*pmegNumPtr];
  2975.         if (pmegPtr->pageCount != 0) {
  2976.             if (vmMachHasVACache) {
  2977.             /* Flush this segment in all contexts */
  2978.             oldContext =  VmMachGetContextReg();
  2979.             for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  2980.                 VmMachSetContextReg(i);
  2981.                 VmMachFlushSegment(virtAddr);
  2982.             }
  2983.             VmMachSetContextReg(oldContext);
  2984.             }
  2985.             VmMachSetSegMap(vmMachPTESegAddr, (int)*pmegNumPtr);
  2986.             skipSeg = FALSE;
  2987.         } else {
  2988.             skipSeg = TRUE;
  2989.         }
  2990.         } else {
  2991.         skipSeg = TRUE;
  2992.         }
  2993.         nextSeg = FALSE;
  2994.     }
  2995.     if (!skipSeg) {
  2996.         /*
  2997.          * Change the hardware page table.
  2998.          */
  2999.         tVirtAddr =
  3000.         ((unsigned int)virtAddr & VMMACH_PAGE_MASK) + vmMachPTESegAddr;
  3001.         for (i = 0; i < VMMACH_CLUSTER_SIZE; i++) {
  3002.         pageVirtAddr = tVirtAddr + i * VMMACH_PAGE_SIZE_INT;
  3003.         pte = VmMachGetPageMap(pageVirtAddr);
  3004.         if (pte & VMMACH_RESIDENT_BIT) {
  3005.             pte &= ~VMMACH_PROTECTION_FIELD;
  3006.             pte |= makeWriteable ? VMMACH_URW_PROT : VMMACH_UR_PROT;
  3007. #ifdef sun4
  3008.             if (virtAddr >= vmStackEndAddr) {
  3009.             pte |= VMMACH_DONT_CACHE_BIT;
  3010.             } else {
  3011.             pte &= ~VMMACH_DONT_CACHE_BIT;
  3012.             }
  3013. #endif /* sun4 */
  3014.             VmMachSetPageMap(pageVirtAddr, pte);
  3015.         }
  3016.         }
  3017.         virtAddr += VMMACH_PAGE_SIZE;
  3018.         firstPage++;
  3019.         if (((unsigned int)virtAddr & VMMACH_PAGE_MASK) == 0) {
  3020.         nextSeg = TRUE;
  3021.         }
  3022.     } else {
  3023.         int    segNum;
  3024.  
  3025.         segNum = PageToSeg(firstPage) + 1;
  3026.         firstPage = SegToPage(segNum);
  3027.         virtAddr = (Address)(firstPage << VMMACH_PAGE_SHIFT);
  3028.         nextSeg = TRUE;
  3029.     }
  3030.     }
  3031.  
  3032.     MASTER_UNLOCK(vmMachMutexPtr);
  3033. }
  3034.  
  3035.  
  3036. /*
  3037.  *----------------------------------------------------------------------
  3038.  *
  3039.  * VmMach_SetPageProt --
  3040.  *
  3041.  *    Set the protection in hardware and software for the given virtual
  3042.  *    page.
  3043.  *
  3044.  * Results:
  3045.  *    None.
  3046.  *
  3047.  * Side effects:
  3048.  *    Page table may be modified for the segment.
  3049.  *
  3050.  *----------------------------------------------------------------------
  3051.  */
  3052. ENTRY void
  3053. VmMach_SetPageProt(virtAddrPtr, softPTE)
  3054.     register    Vm_VirtAddr    *virtAddrPtr;    /* The virtual page to set the
  3055.                          * protection for.*/
  3056.     Vm_PTE            softPTE;    /* Software pte. */
  3057. {
  3058.     register    VmMachPTE     hardPTE;
  3059.     register    VmMach_SegData    *machPtr;
  3060.     Address               virtAddr;
  3061.     int                pmegNum;
  3062.     int                i;
  3063. #ifdef sun4
  3064.     Address            testVirtAddr;
  3065. #endif /* sun4 */
  3066.     int                j;
  3067.     int                oldContext;
  3068.  
  3069.     MASTER_LOCK(vmMachMutexPtr);
  3070.  
  3071.     machPtr = virtAddrPtr->segPtr->machPtr;
  3072.     pmegNum = *GetHardSegPtr(machPtr, PageToOffSeg(virtAddrPtr->page,
  3073.         virtAddrPtr));
  3074.     if (pmegNum != VMMACH_INV_PMEG) {
  3075.     virtAddr = ((virtAddrPtr->page << VMMACH_PAGE_SHIFT) & 
  3076.             VMMACH_PAGE_MASK) + vmMachPTESegAddr;    
  3077. #ifdef sun4
  3078.     testVirtAddr = (Address) (virtAddrPtr->page << VMMACH_PAGE_SHIFT);
  3079. #endif sun4
  3080.     for (i = 0; 
  3081.          i < VMMACH_CLUSTER_SIZE; 
  3082.          i++, virtAddr += VMMACH_PAGE_SIZE_INT) {
  3083.         hardPTE = VmMachReadPTE(pmegNum, virtAddr);
  3084.         hardPTE &= ~VMMACH_PROTECTION_FIELD;
  3085.         hardPTE |= (softPTE & (VM_COW_BIT | VM_READ_ONLY_PROT)) ? 
  3086.                     VMMACH_UR_PROT : VMMACH_URW_PROT;
  3087. #ifdef sun4
  3088.         if (testVirtAddr >= vmStackEndAddr) {
  3089.         hardPTE |= VMMACH_DONT_CACHE_BIT;
  3090.         } else {
  3091.         hardPTE &= ~VMMACH_DONT_CACHE_BIT;
  3092.         }
  3093. #endif /* sun4 */
  3094.         if (vmMachHasVACache) {
  3095.         /* Flush this page in all contexts */
  3096.         oldContext =  VmMachGetContextReg();
  3097.         for (j = 0; j < VMMACH_NUM_CONTEXTS; j++) {
  3098.             VmMachSetContextReg(j);
  3099.             FLUSH_ALL_PAGE(testVirtAddr);
  3100.         }
  3101.         VmMachSetContextReg(oldContext);
  3102.         }
  3103.         VmMachWritePTE(pmegNum, virtAddr, hardPTE);
  3104.     }
  3105.     }
  3106.  
  3107.     MASTER_UNLOCK(vmMachMutexPtr);
  3108. }
  3109.  
  3110.  
  3111. /*
  3112.  * ----------------------------------------------------------------------------
  3113.  *
  3114.  * VmMach_AllocCheck --
  3115.  *
  3116.  *      Determine if this page can be reallocated.  A page can be reallocated
  3117.  *    if it has not been referenced or modified.
  3118.  *  
  3119.  * Results:
  3120.  *      None.
  3121.  *
  3122.  * Side effects:
  3123.  *      The given page will be invalidated in the hardware if it has not
  3124.  *    been referenced and *refPtr and *modPtr will have the hardware 
  3125.  *    reference and modify bits or'd in.
  3126.  *
  3127.  * ----------------------------------------------------------------------------
  3128.  */
  3129. ENTRY void
  3130. VmMach_AllocCheck(virtAddrPtr, virtFrameNum, refPtr, modPtr)
  3131.     register    Vm_VirtAddr    *virtAddrPtr;
  3132.     unsigned    int        virtFrameNum;
  3133.     register    Boolean        *refPtr;
  3134.     register    Boolean        *modPtr;
  3135. {
  3136.     register VmMach_SegData    *machPtr;
  3137.     register VmMachPTE         hardPTE;  
  3138.     int                pmegNum; 
  3139.     Address            virtAddr;
  3140.     int                i;
  3141.     int                origMod;
  3142.  
  3143.     MASTER_LOCK(vmMachMutexPtr);
  3144.  
  3145.     origMod = *modPtr;
  3146.  
  3147.     *refPtr |= refModMap[virtFrameNum] & VMMACH_REFERENCED_BIT;
  3148.     *modPtr = refModMap[virtFrameNum] & VMMACH_MODIFIED_BIT;
  3149.     if (!*refPtr || !*modPtr) {
  3150.     machPtr = virtAddrPtr->segPtr->machPtr;
  3151.     pmegNum = *GetHardSegPtr(machPtr, PageToOffSeg(virtAddrPtr->page,
  3152.         virtAddrPtr));
  3153.     if (pmegNum != VMMACH_INV_PMEG) {
  3154.         hardPTE = 0;
  3155.         virtAddr = 
  3156.         ((virtAddrPtr->page << VMMACH_PAGE_SHIFT) & VMMACH_PAGE_MASK) + 
  3157.             vmMachPTESegAddr;
  3158.         for (i = 0; i < VMMACH_CLUSTER_SIZE; i++ ) {
  3159.         hardPTE |= VmMachReadPTE(pmegNum, 
  3160.                     virtAddr + i * VMMACH_PAGE_SIZE_INT);
  3161.         }
  3162.         *refPtr |= hardPTE & VMMACH_REFERENCED_BIT;
  3163.         *modPtr |= hardPTE & VMMACH_MODIFIED_BIT;
  3164.     }
  3165.     }
  3166.     if (!*refPtr) {
  3167.     /*
  3168.      * Invalidate the page so that it will force a fault if it is
  3169.      * referenced.  Since our caller has blocked all faults on this
  3170.      * page, by invalidating it we can guarantee that the reference and
  3171.      * modify information that we are returning will be valid until
  3172.      * our caller reenables faults on this page.
  3173.      */
  3174.     PageInvalidate(virtAddrPtr, virtFrameNum, FALSE);
  3175.  
  3176.     if (origMod && !*modPtr) {
  3177.         /*
  3178.          * This page had the modify bit set in software but not in
  3179.          * hardware.
  3180.          */
  3181.         vmStat.notHardModPages++;
  3182.     }
  3183.     }
  3184.     *modPtr |= origMod;
  3185.  
  3186.     MASTER_UNLOCK(vmMachMutexPtr);
  3187.  
  3188. }
  3189.  
  3190.  
  3191. /*
  3192.  * ----------------------------------------------------------------------------
  3193.  *
  3194.  * VmMach_GetRefModBits --
  3195.  *
  3196.  *      Pull the reference and modified bits out of hardware.
  3197.  *  
  3198.  * Results:
  3199.  *      None.
  3200.  *
  3201.  * Side effects:
  3202.  *      
  3203.  *
  3204.  * ----------------------------------------------------------------------------
  3205.  */
  3206. ENTRY void
  3207. VmMach_GetRefModBits(virtAddrPtr, virtFrameNum, refPtr, modPtr)
  3208.     register    Vm_VirtAddr    *virtAddrPtr;
  3209.     unsigned    int        virtFrameNum;
  3210.     register    Boolean        *refPtr;
  3211.     register    Boolean        *modPtr;
  3212. {
  3213.     register VmMach_SegData    *machPtr;
  3214.     register VmMachPTE         hardPTE;  
  3215.     int                pmegNum; 
  3216.     Address            virtAddr;
  3217.     int                i;
  3218.  
  3219.     MASTER_LOCK(vmMachMutexPtr);
  3220.  
  3221.     *refPtr = refModMap[virtFrameNum] & VMMACH_REFERENCED_BIT;
  3222.     *modPtr = refModMap[virtFrameNum] & VMMACH_MODIFIED_BIT;
  3223.     if (!*refPtr || !*modPtr) {
  3224.     machPtr = virtAddrPtr->segPtr->machPtr;
  3225.     pmegNum = *GetHardSegPtr(machPtr, PageToOffSeg(virtAddrPtr->page,
  3226.         virtAddrPtr));
  3227.     if (pmegNum != VMMACH_INV_PMEG) {
  3228.         hardPTE = 0;
  3229.         virtAddr = 
  3230.         ((virtAddrPtr->page << VMMACH_PAGE_SHIFT) & VMMACH_PAGE_MASK) + 
  3231.             vmMachPTESegAddr;
  3232.         for (i = 0; i < VMMACH_CLUSTER_SIZE; i++ ) {
  3233.         hardPTE |= VmMachReadPTE(pmegNum, 
  3234.                     virtAddr + i * VMMACH_PAGE_SIZE_INT);
  3235.         }
  3236.         if (!*refPtr) {
  3237.         *refPtr = hardPTE & VMMACH_REFERENCED_BIT;
  3238.         }
  3239.         if (!*modPtr) {
  3240.         *modPtr = hardPTE & VMMACH_MODIFIED_BIT;
  3241.         }
  3242.     }
  3243.     }
  3244.  
  3245.     MASTER_UNLOCK(vmMachMutexPtr);
  3246.     return;
  3247. }
  3248.  
  3249.  
  3250. /*
  3251.  * ----------------------------------------------------------------------------
  3252.  *
  3253.  * VmMach_ClearRefBit --
  3254.  *
  3255.  *      Clear the reference bit at the given virtual address.
  3256.  *
  3257.  * Results:
  3258.  *      None.
  3259.  *
  3260.  * Side effects:
  3261.  *      Hardware reference bit cleared.
  3262.  *
  3263.  * ----------------------------------------------------------------------------
  3264.  */
  3265. ENTRY void
  3266. VmMach_ClearRefBit(virtAddrPtr, virtFrameNum)
  3267.     register    Vm_VirtAddr    *virtAddrPtr;
  3268.     unsigned     int        virtFrameNum;
  3269. {
  3270.     register    VmMach_SegData    *machPtr;
  3271.     int                pmegNum;
  3272.     Address            virtAddr;
  3273.     int                i;
  3274.     VmMachPTE            pte;
  3275.  
  3276.     MASTER_LOCK(vmMachMutexPtr);
  3277.  
  3278.     refModMap[virtFrameNum] &= ~VMMACH_REFERENCED_BIT;
  3279.     machPtr = virtAddrPtr->segPtr->machPtr;
  3280.     pmegNum = *GetHardSegPtr(machPtr, PageToOffSeg(virtAddrPtr->page,
  3281.         virtAddrPtr));
  3282.     if (pmegNum != VMMACH_INV_PMEG) {
  3283.     virtAddr = ((virtAddrPtr->page << VMMACH_PAGE_SHIFT) & 
  3284.             VMMACH_PAGE_MASK) + vmMachPTESegAddr;
  3285.     for (i = 0; 
  3286.          i < VMMACH_CLUSTER_SIZE;
  3287.          i++, virtAddr += VMMACH_PAGE_SIZE_INT) {
  3288.         pte = VmMachReadPTE(pmegNum, virtAddr);
  3289.         pte &= ~VMMACH_REFERENCED_BIT;
  3290.         VmMachWritePTE(pmegNum, virtAddr, pte);
  3291.     }
  3292.     }
  3293.  
  3294.     MASTER_UNLOCK(vmMachMutexPtr);
  3295.     return;
  3296. }
  3297.  
  3298.  
  3299. /*
  3300.  * ----------------------------------------------------------------------------
  3301.  *
  3302.  * VmMach_ClearModBit --
  3303.  *
  3304.  *      Clear the modified bit at the given virtual address.
  3305.  *
  3306.  * Results:
  3307.  *      None.
  3308.  *
  3309.  * Side effects:
  3310.  *      Hardware modified bit cleared.
  3311.  *
  3312.  * ----------------------------------------------------------------------------
  3313.  */
  3314. ENTRY void
  3315. VmMach_ClearModBit(virtAddrPtr, virtFrameNum)
  3316.     register    Vm_VirtAddr    *virtAddrPtr;
  3317.     unsigned    int        virtFrameNum;
  3318. {
  3319.     register    VmMach_SegData    *machPtr;
  3320.     int                pmegNum;
  3321.     Address            virtAddr;
  3322.     int                i;
  3323.     Vm_PTE            pte;
  3324.  
  3325.     MASTER_LOCK(vmMachMutexPtr);
  3326.  
  3327.     refModMap[virtFrameNum] &= ~VMMACH_MODIFIED_BIT;
  3328.     machPtr = virtAddrPtr->segPtr->machPtr;
  3329.     pmegNum = *GetHardSegPtr(machPtr, PageToOffSeg(virtAddrPtr->page,
  3330.         virtAddrPtr));
  3331.     if (pmegNum != VMMACH_INV_PMEG) {
  3332.     virtAddr = ((virtAddrPtr->page << VMMACH_PAGE_SHIFT) & 
  3333.             VMMACH_PAGE_MASK) + vmMachPTESegAddr;
  3334.     for (i = 0; 
  3335.          i < VMMACH_CLUSTER_SIZE; 
  3336.          i++, virtAddr += VMMACH_PAGE_SIZE_INT) {
  3337.         pte = VmMachReadPTE(pmegNum, virtAddr);
  3338.         pte &= ~VMMACH_MODIFIED_BIT;
  3339.         VmMachWritePTE(pmegNum, virtAddr, pte);
  3340.     }
  3341.     }
  3342.  
  3343.     MASTER_UNLOCK(vmMachMutexPtr);
  3344.     return;
  3345. }
  3346.  
  3347.  
  3348. /*
  3349.  * ----------------------------------------------------------------------------
  3350.  *
  3351.  * VmMach_PageValidate --
  3352.  *
  3353.  *      Validate a page for the given virtual address.  It is assumed that when
  3354.  *      this routine is called that the user context register contains the
  3355.  *    context in which the page will be validated.
  3356.  *
  3357.  * Results:
  3358.  *      None.
  3359.  *
  3360.  * Side effects:
  3361.  *      The page table and hardware segment tables associated with the segment
  3362.  *      are modified to validate the page.
  3363.  *
  3364.  * ----------------------------------------------------------------------------
  3365.  */
  3366.  
  3367. ENTRY void
  3368. VmMach_PageValidate(virtAddrPtr, pte) 
  3369.     register    Vm_VirtAddr    *virtAddrPtr;
  3370.     Vm_PTE            pte;
  3371. {
  3372.     register  Vm_Segment    *segPtr;
  3373.     register  VMMACH_SEG_NUM    *segTablePtr;
  3374.     register  PMEG        *pmegPtr;
  3375.     register  int        hardSeg;
  3376.     register  VmMachPTE        hardPTE;
  3377.     register  VmMachPTE        tHardPTE;
  3378.     struct    VmMach_PMEGseg    *pmegSegPtr;
  3379.     Vm_PTE    *ptePtr;
  3380.     Address    addr;
  3381.     Boolean    reLoadPMEG;      /* TRUE if we had to reload this PMEG. */
  3382.     int        i;
  3383.     int        tmpSegNum;
  3384.  
  3385.     MASTER_LOCK(vmMachMutexPtr);
  3386.  
  3387.     segPtr = virtAddrPtr->segPtr;
  3388.     addr = (Address) (virtAddrPtr->page << VMMACH_PAGE_SHIFT);
  3389. #ifdef sun4
  3390.     if (!VMMACH_ADDR_CHECK(addr)) {
  3391.     panic("VmMach_PageValidate: virt addr 0x%x falls into illegal range!\n",
  3392.         addr);
  3393.     }
  3394. #endif sun4
  3395.  
  3396.     /*
  3397.      * Find out the hardware segment that has to be mapped.
  3398.      * If this is a mapping segment, this gives us the seg num
  3399.      * for the segment in the other process and the segPtr is the mapSegPtr
  3400.      * which is set to the segPtr of the other process.
  3401.      */
  3402.  
  3403.     hardSeg = PageToOffSeg(virtAddrPtr->page, virtAddrPtr);
  3404.  
  3405.     segTablePtr = (VMMACH_SEG_NUM *) GetHardSegPtr(segPtr->machPtr, hardSeg);
  3406.     pmegPtr = &pmegArray[*segTablePtr]; /* Software seg's pmeg. */
  3407.     tmpSegNum = VmMachGetSegMap(addr);  /* Hardware seg's pmeg. */
  3408.     if (tmpSegNum != VMMACH_INV_PMEG && tmpSegNum != (int)*segTablePtr) {
  3409.     if (!(Proc_GetCurrentProc()->vmPtr->vmFlags & VM_COPY_IN_PROGRESS)) {
  3410.         if (*segTablePtr != VMMACH_INV_PMEG) {
  3411.         if (debugVmStubs) {
  3412.             printf("VmMach_PageValidate: multiple pmegs used!\n");
  3413.             printf(" seg = %d, pmeg %d,%d, proc=%x %s\n",
  3414.                 segPtr->segNum, *segTablePtr, tmpSegNum,
  3415.                 Proc_GetCurrentProc()->processID,
  3416.                 Proc_GetCurrentProc()->argString);
  3417.             printf("  old seg = %x\n",
  3418.                 pmegArray[tmpSegNum].segInfo.segPtr->segNum);
  3419.             printf("Freeing pmeg %d\n", *segTablePtr);
  3420.         }
  3421.         PMEGFree(*segTablePtr);
  3422.         }
  3423.         if (debugVmStubs) {
  3424.         printf("Multiple segs in hard segment: seg = %d, pmeg %d,%d, proc=%x %s\n",
  3425.             segPtr->segNum, *segTablePtr, tmpSegNum,
  3426.             Proc_GetCurrentProc()->processID,
  3427.             Proc_GetCurrentProc()->argString);
  3428.         }
  3429.  
  3430.         *segTablePtr = (VMMACH_SEG_NUM) tmpSegNum;
  3431.         pmegPtr = &pmegArray[*segTablePtr];
  3432.         if (virtAddrPtr->segPtr->machPtr->pmegInfo.inuse) {
  3433.         printf("VmMach_PageValidate: segment sharing table overflow\n");
  3434.         } else {
  3435.         pmegSegPtr = &virtAddrPtr->segPtr->machPtr->pmegInfo;
  3436.         pmegSegPtr->inuse = 1;
  3437.         pmegSegPtr->nextLink = pmegPtr->segInfo.nextLink;
  3438.         pmegPtr->segInfo.nextLink = pmegSegPtr;
  3439.         pmegSegPtr->segPtr = virtAddrPtr->segPtr;
  3440.         pmegSegPtr->hardSegNum = hardSeg;
  3441.         }
  3442.     }
  3443.     }
  3444.  
  3445.     reLoadPMEG = FALSE;
  3446.     if (*segTablePtr == VMMACH_INV_PMEG) {
  3447.     int flags;
  3448.     /*
  3449.      * If there is not already a pmeg for this hardware segment, then get
  3450.      * one and initialize it.  If this is for the kernel then make
  3451.      * sure that the pmeg cannot be taken away from the kernel.
  3452.      * We make an exception for PMEGs allocated only for the block cache.
  3453.      * If we fault on kernel pmeg we reload all the mappings for the
  3454.      * pmeg because we can't tolerate "quick" faults in some places in the
  3455.      * kernel.
  3456.      */
  3457.     flags = 0;
  3458.     if (segPtr == vm_SysSegPtr) {
  3459.        if (IN_FILE_CACHE_SEG(addr) && vmMachCanStealFileCachePmegs) {
  3460.           /*
  3461.            * In block cache virtual addresses.
  3462.            */
  3463.           reLoadPMEG = TRUE;
  3464.        } else {
  3465.           /*
  3466.            * Normal kernel PMEGs must still be wired.
  3467.            */
  3468.           flags = PMEG_DONT_ALLOC;
  3469.        }
  3470.     }
  3471.         *segTablePtr = PMEGGet(segPtr, hardSeg, flags);
  3472.     pmegPtr = &pmegArray[*segTablePtr];
  3473.     } else {
  3474.     pmegPtr = &pmegArray[*segTablePtr];
  3475.     if (pmegPtr->pageCount == 0) {
  3476.         /*
  3477.          * We are using a PMEG that had a pagecount of 0.  In this case
  3478.          * it was put onto the end of the free pmeg list in anticipation
  3479.          * of someone stealing this empty pmeg.  Now we have to move
  3480.          * it off of the free list.
  3481.          */
  3482.         if (pmegPtr->flags & PMEG_DONT_ALLOC) {
  3483.         List_Remove((List_Links *)pmegPtr);
  3484.         } else {
  3485.         List_Move((List_Links *)pmegPtr, LIST_ATREAR(pmegInuseList));
  3486.         }
  3487.     }
  3488.     }
  3489.     hardPTE = VMMACH_RESIDENT_BIT | VirtToPhysPage(Vm_GetPageFrame(pte));
  3490. #ifdef sun4
  3491.     if (addr < (Address) VMMACH_DEV_START_ADDR) {
  3492.         hardPTE &= ~VMMACH_DONT_CACHE_BIT;
  3493.     } else {
  3494.     hardPTE |= VMMACH_DONT_CACHE_BIT;
  3495.     }
  3496. #endif /* sun4 */
  3497.     if (segPtr == vm_SysSegPtr) {
  3498.     int    oldContext;
  3499.     /*
  3500.      * Have to propagate the PMEG to all contexts.
  3501.      */
  3502.     oldContext = VmMachGetContextReg();
  3503.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  3504.         VmMachSetContextReg(i);
  3505.         VmMachSetSegMap(addr, (int)*segTablePtr);
  3506.     }
  3507.     VmMachSetContextReg(oldContext);
  3508.     hardPTE |= VMMACH_KRW_PROT;
  3509.     } else {
  3510.     Proc_ControlBlock    *procPtr;
  3511.     VmProcLink        *procLinkPtr;
  3512.     VmMach_Context      *contextPtr;
  3513.  
  3514.     procPtr = Proc_GetCurrentProc();
  3515.     if (virtAddrPtr->flags & USING_MAPPED_SEG) {
  3516.         addr = (Address) (VMMACH_MAP_SEG_ADDR + 
  3517.                 ((unsigned int)addr & (VMMACH_SEG_SIZE - 1)));
  3518.         /* PUT IT IN SOFTWARE OF MAP AREA FOR PROCESS */
  3519.         procPtr->vmPtr->machPtr->contextPtr->map[MAP_SEG_NUM] =
  3520.             *segTablePtr;
  3521.     } else{
  3522.         /* update it for regular seg num */
  3523.         procPtr->vmPtr->machPtr->contextPtr->map[hardSeg] = *segTablePtr;
  3524.     }
  3525.     VmMachSetSegMap(addr, (int)*segTablePtr);
  3526.  
  3527.         if (segPtr != (Vm_Segment *) NIL) {
  3528.             LIST_FORALL(segPtr->procList, (List_Links *)procLinkPtr) {
  3529.         if (procLinkPtr->procPtr->vmPtr != (Vm_ProcInfo *) NIL &&
  3530.             procLinkPtr->procPtr->vmPtr->machPtr !=
  3531.             (VmMach_ProcData *) NIL &&
  3532.             (contextPtr =
  3533.             procLinkPtr->procPtr->vmPtr->machPtr->contextPtr) !=
  3534.             (VmMach_Context *) NIL) {
  3535.             contextPtr->map[hardSeg] = *segTablePtr;
  3536.         }
  3537.         }
  3538.     }
  3539.  
  3540.     if ((pte & (VM_COW_BIT | VM_READ_ONLY_PROT)) ||
  3541.         (virtAddrPtr->flags & VM_READONLY_SEG)) {
  3542.         hardPTE |= VMMACH_UR_PROT;
  3543.     } else {
  3544.         hardPTE |= VMMACH_URW_PROT;
  3545.     }
  3546.     }
  3547.     tHardPTE = VmMachGetPageMap(addr);
  3548.     if (tHardPTE & VMMACH_RESIDENT_BIT) {
  3549.     hardPTE |= tHardPTE & (VMMACH_REFERENCED_BIT | VMMACH_MODIFIED_BIT);
  3550.     for (i = 1; i < VMMACH_CLUSTER_SIZE; i++ ) {
  3551.         hardPTE |= VmMachGetPageMap(addr + i * VMMACH_PAGE_SIZE_INT) & 
  3552.                 (VMMACH_REFERENCED_BIT | VMMACH_MODIFIED_BIT);
  3553.     }
  3554.     } else {
  3555.     if (*segTablePtr == VMMACH_INV_PMEG) {
  3556.         panic("Invalid pmeg\n");
  3557.     }
  3558.     pmegArray[*segTablePtr].pageCount++;
  3559.     }
  3560.     /* Flush something? */
  3561.     SET_ALL_PAGE_MAP(addr, hardPTE);
  3562.     if (reLoadPMEG) {
  3563.     /*
  3564.      * Reload all pte's for this pmeg.
  3565.      */
  3566.     unsigned int a = (hardSeg << VMMACH_SEG_SHIFT);
  3567.     int    pageCount = 0;
  3568.     for (i = 0; i < VMMACH_NUM_PAGES_PER_SEG; i++ ) { 
  3569.         ptePtr = VmGetPTEPtr(vm_SysSegPtr, (a >> VMMACH_PAGE_SHIFT));
  3570.         if ((*ptePtr & VM_PHYS_RES_BIT)) {
  3571.         hardPTE = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT | 
  3572.                 VirtToPhysPage(Vm_GetPageFrame(*ptePtr));
  3573.         SET_ALL_PAGE_MAP(a, hardPTE);
  3574.         pageCount++;
  3575.          }
  3576.          a += VMMACH_PAGE_SIZE;
  3577.     }
  3578.     if (pmegPtr-pmegArray == VMMACH_INV_PMEG) {
  3579.         panic("Invalid pmeg\n");
  3580.     }
  3581.     pmegPtr->pageCount = pageCount;
  3582.     }
  3583.  
  3584.     MASTER_UNLOCK(vmMachMutexPtr);
  3585.     return;
  3586. }
  3587.  
  3588.  
  3589. /*
  3590.  * ----------------------------------------------------------------------------
  3591.  *
  3592.  * PageInvalidate --
  3593.  *
  3594.  *      Invalidate a page for the given segment.  
  3595.  *
  3596.  * Results:
  3597.  *      None.
  3598.  *
  3599.  * Side effects:
  3600.  *      The page table and hardware segment tables associated with the segment
  3601.  *      are modified to invalidate the page.
  3602.  *
  3603.  * ----------------------------------------------------------------------------
  3604.  */
  3605. static void
  3606. PageInvalidate(virtAddrPtr, virtPage, segDeletion) 
  3607.     register    Vm_VirtAddr    *virtAddrPtr;
  3608.     unsigned     int        virtPage;
  3609.     Boolean            segDeletion;
  3610. {
  3611.     register VmMach_SegData    *machPtr;
  3612.     register PMEG        *pmegPtr;
  3613.     VmMachPTE            hardPTE;
  3614.     int                pmegNum;
  3615.     Address            addr;
  3616.     int                i;
  3617.     Address            testVirtAddr;
  3618.     VmProcLink              *flushProcLinkPtr;
  3619.     Vm_Segment              *flushSegPtr;
  3620.     Vm_ProcInfo             *flushVmPtr;
  3621.     VmMach_ProcData         *flushMachPtr;
  3622.     VmMach_Context          *flushContextPtr;
  3623.     unsigned int            flushContext;
  3624.     unsigned int            oldContext;
  3625.  
  3626.     refModMap[virtPage] = 0;
  3627.     if (segDeletion) {
  3628.     return;
  3629.     }
  3630.     machPtr = virtAddrPtr->segPtr->machPtr;
  3631.     pmegNum = *GetHardSegPtr(machPtr, PageToOffSeg(virtAddrPtr->page,
  3632.         virtAddrPtr));
  3633.     if (pmegNum == VMMACH_INV_PMEG) {
  3634.     return;
  3635.     }
  3636.     testVirtAddr = (Address) (virtAddrPtr->page << VMMACH_PAGE_SHIFT);
  3637.     addr = ((virtAddrPtr->page << VMMACH_PAGE_SHIFT) &
  3638.                 VMMACH_PAGE_MASK) + vmMachPTESegAddr;
  3639. #ifdef sun4
  3640.     if (!VMMACH_ADDR_CHECK(addr)) {
  3641.     panic("PageInvalidate: virt addr 0x%x falls into illegal range!\n",
  3642.         addr);
  3643.     }
  3644. #endif sun4
  3645.     hardPTE = VmMachReadPTE(pmegNum, addr);
  3646.     /*
  3647.      * Invalidate the page table entry.  There's no need to flush the page if
  3648.      * the invalidation is due to segment deletion, since the whole segment
  3649.      * will already have been flushed.  Flush the page in the context in which
  3650.      * it was validated.
  3651.      */
  3652.     if (!segDeletion && vmMachHasVACache) {
  3653.     int    flushedP = FALSE;
  3654.  
  3655.         flushSegPtr = virtAddrPtr->segPtr;
  3656.         if (flushSegPtr != (Vm_Segment *) NIL) {
  3657.             LIST_FORALL(flushSegPtr->procList, (List_Links *)flushProcLinkPtr) {
  3658.                 flushVmPtr = flushProcLinkPtr->procPtr->vmPtr;
  3659.                 if (flushVmPtr != (Vm_ProcInfo *) NIL) {
  3660.                     flushMachPtr = flushVmPtr->machPtr;
  3661.                     if (flushMachPtr != (VmMach_ProcData *) NIL) {
  3662.                         flushContextPtr = flushMachPtr->contextPtr;
  3663.                         if (flushContextPtr != (VmMach_Context *) NIL) {
  3664.                             flushContext = flushContextPtr->context;
  3665.                             /* save old context */
  3666.                             oldContext = VmMachGetContextReg();
  3667.                             /* move to page's context */
  3668.                             VmMachSetContextReg((int)flushContext);
  3669.                             /* flush page in its context */
  3670.                             FLUSH_ALL_PAGE(testVirtAddr);
  3671.                             /* back to old context */
  3672.                             VmMachSetContextReg((int)oldContext);
  3673.                 flushedP = TRUE;
  3674.                         }
  3675.                     }
  3676.                 }
  3677.             }
  3678.         }
  3679.     if (!flushedP) {
  3680.         FLUSH_ALL_PAGE(testVirtAddr);
  3681.     }
  3682.     }
  3683.     for (i = 0; i < VMMACH_CLUSTER_SIZE; i++, addr += VMMACH_PAGE_SIZE_INT) {
  3684.     VmMachWritePTE(pmegNum, addr, (VmMachPTE)0);
  3685.     }
  3686.     pmegPtr = &pmegArray[pmegNum];
  3687.     if (hardPTE & VMMACH_RESIDENT_BIT) {
  3688.     pmegPtr->pageCount--;
  3689.     if (pmegPtr->pageCount == 0) {
  3690.         /*
  3691.          * When the pageCount goes to zero, the pmeg is put onto the end
  3692.          * of the free list so that it can get freed if someone else
  3693.          * needs a pmeg.  It isn't freed here because there is a fair
  3694.          * amount of overhead when freeing a pmeg so its best to keep
  3695.          * it around in case it is needed again.
  3696.          */
  3697.         if (pmegPtr->flags & PMEG_DONT_ALLOC) {
  3698.         List_Insert((List_Links *)pmegPtr, 
  3699.                 LIST_ATREAR(pmegFreeList));
  3700.         } else {
  3701.         List_Move((List_Links *)pmegPtr, 
  3702.               LIST_ATREAR(pmegFreeList));
  3703.         }
  3704.     }
  3705.     }
  3706.     return;
  3707. }
  3708.  
  3709.  
  3710.  
  3711. /*
  3712.  * ----------------------------------------------------------------------------
  3713.  *
  3714.  * VmMach_PageInvalidate --
  3715.  *
  3716.  *      Invalidate a page for the given segment.  
  3717.  *
  3718.  * Results:
  3719.  *      None.
  3720.  *
  3721.  * Side effects:
  3722.  *      The page table and hardware segment tables associated with the segment
  3723.  *      are modified to invalidate the page.
  3724.  *
  3725.  * ----------------------------------------------------------------------------
  3726.  */
  3727. ENTRY void
  3728. VmMach_PageInvalidate(virtAddrPtr, virtPage, segDeletion) 
  3729.     register    Vm_VirtAddr    *virtAddrPtr;
  3730.     unsigned     int        virtPage;
  3731.     Boolean            segDeletion;
  3732. {
  3733.     MASTER_LOCK(vmMachMutexPtr);
  3734.  
  3735.     PageInvalidate(virtAddrPtr, virtPage, segDeletion);
  3736.  
  3737.     MASTER_UNLOCK(vmMachMutexPtr);
  3738.     return;
  3739. }
  3740.  
  3741.  
  3742. /*
  3743.  *----------------------------------------------------------------------
  3744.  *
  3745.  * VmMach_PinUserPages --
  3746.  *
  3747.  *    Force a user page to be resident in memory.
  3748.  *
  3749.  * Results:
  3750.  *    None.
  3751.  *
  3752.  * Side effects:
  3753.  *    None.
  3754.  *
  3755.  *----------------------------------------------------------------------
  3756.  */
  3757. /*ARGSUSED*/
  3758. void
  3759. VmMach_PinUserPages(mapType, virtAddrPtr, lastPage)
  3760.     int        mapType;
  3761.     Vm_VirtAddr    *virtAddrPtr;
  3762.     int        lastPage;
  3763. {
  3764.     int                *intPtr;
  3765.     int                dummy;
  3766.     register VmMach_SegData    *machPtr;
  3767.     register int        firstSeg;
  3768.     register int        lastSeg;
  3769.  
  3770.     machPtr = virtAddrPtr->segPtr->machPtr;
  3771.  
  3772.     firstSeg = PageToOffSeg(virtAddrPtr->page, virtAddrPtr);
  3773.     lastSeg = PageToOffSeg(lastPage, virtAddrPtr);
  3774.     /*
  3775.      * Lock down the PMEG behind the first segment.
  3776.      */
  3777.     intPtr = (int *) (virtAddrPtr->page << VMMACH_PAGE_SHIFT);
  3778.     while (!PMEGLock(machPtr, firstSeg)) {
  3779.     /*
  3780.      * Touch the page to bring it into memory.  We know that we can
  3781.      * safely touch it because we wouldn't have been called if these
  3782.      * weren't good addresses.
  3783.      */
  3784.     dummy = *intPtr;
  3785.     }
  3786.     /*
  3787.      * Lock down the rest of the segments.
  3788.      */
  3789.     for (firstSeg++; firstSeg <= lastSeg; firstSeg++) {
  3790.     intPtr = (int *)(firstSeg << VMMACH_SEG_SHIFT);
  3791.     while (!PMEGLock(machPtr, firstSeg)) {
  3792.         dummy = *intPtr;
  3793.     }
  3794.     }
  3795. #ifdef lint
  3796.     dummy = dummy;
  3797. #endif
  3798.     return;
  3799. }
  3800.  
  3801.  
  3802. /*
  3803.  *----------------------------------------------------------------------
  3804.  *
  3805.  * VmMach_UnpinUserPages --
  3806.  *
  3807.  *    Allow a page that was pinned to be unpinned.
  3808.  *
  3809.  * Results:
  3810.  *    None.
  3811.  *
  3812.  * Side effects:
  3813.  *    None.
  3814.  *
  3815.  *----------------------------------------------------------------------
  3816.  */
  3817. ENTRY void
  3818. VmMach_UnpinUserPages(virtAddrPtr, lastPage)
  3819.     Vm_VirtAddr    *virtAddrPtr;
  3820.     int        lastPage;
  3821. {
  3822.     register int    firstSeg;
  3823.     register int    lastSeg;
  3824.     int            pmegNum;
  3825.     register VmMach_SegData    *machPtr;
  3826.  
  3827.     MASTER_LOCK(vmMachMutexPtr);
  3828.  
  3829.     machPtr = virtAddrPtr->segPtr->machPtr;
  3830.     firstSeg = PageToOffSeg(virtAddrPtr->page, virtAddrPtr);
  3831.     lastSeg = PageToOffSeg(lastPage, virtAddrPtr);
  3832.     for (; firstSeg <= lastSeg; firstSeg++) {
  3833.     pmegNum = *GetHardSegPtr(machPtr, firstSeg);
  3834.     if (pmegNum == VMMACH_INV_PMEG) {
  3835.         MASTER_UNLOCK(vmMachMutexPtr);
  3836.         panic("Pinned PMEG invalid???\n");
  3837.         return;
  3838.     }
  3839.     pmegArray[pmegNum].lockCount--;
  3840.     }
  3841.  
  3842.     MASTER_UNLOCK(vmMachMutexPtr);
  3843.     return;
  3844. }
  3845.  
  3846.  
  3847. /*
  3848.  ----------------------------------------------------------------------
  3849.  *
  3850.  * VmMach_MapInDevice --
  3851.  *
  3852.  *    Map a device at some physical address into kernel virtual address.
  3853.  *    This is for use by the controller initialization routines.
  3854.  *    This routine looks for a free page in the special range of
  3855.  *    kernel virtual that is reserved for this kind of thing and
  3856.  *    sets up the page table so that it references the device.
  3857.  *
  3858.  * Results:
  3859.  *    The kernel virtual address needed to reference the device is returned.
  3860.  *
  3861.  * Side effects:
  3862.  *    The hardware page table is modified.  This may steal another
  3863.  *    page from kernel virtual space, unless a page can be cleverly re-used.
  3864.  *
  3865.  *----------------------------------------------------------------------
  3866.  */
  3867. Address
  3868. VmMach_MapInDevice(devPhysAddr, type)
  3869.     Address    devPhysAddr;    /* Physical address of the device to map in */
  3870.     int        type;        /* Value for the page table entry type field.
  3871.                  * This depends on the address space that
  3872.                  * the devices live in, ie. VME D16 or D32 */
  3873. {
  3874.     Address         virtAddr;
  3875.     Address        freeVirtAddr = (Address)0;
  3876.     Address        freePMEGAddr = (Address)0;
  3877.     int            page;
  3878.     int            pageFrame;
  3879.     VmMachPTE        pte;
  3880.  
  3881.     /*
  3882.      * Get the page frame for the physical device so we can
  3883.      * compare it against existing pte's.
  3884.      */
  3885.     pageFrame = ((unsigned)devPhysAddr >> VMMACH_PAGE_SHIFT_INT)
  3886.     & VMMACH_PAGE_FRAME_FIELD;
  3887.  
  3888.     /*
  3889.      * Spin through the segments and their pages looking for a free
  3890.      * page or a virtual page that is already mapped to the physical page.
  3891.      */
  3892.     for (virtAddr = (Address)VMMACH_DEV_START_ADDR;
  3893.          virtAddr < (Address)VMMACH_DEV_END_ADDR; ) {
  3894.     if (VmMachGetSegMap(virtAddr) == VMMACH_INV_PMEG) {
  3895.         /* 
  3896.          * If we can't find any free mappings we can use this PMEG.
  3897.          */
  3898.         if (freePMEGAddr == 0) {
  3899.         freePMEGAddr = virtAddr;
  3900.         }
  3901.         virtAddr += VMMACH_SEG_SIZE;
  3902.         continue;
  3903.     }
  3904.     /*
  3905.      * Careful, use the correct page size when incrementing virtAddr.
  3906.      * Use the real hardware size (ignore software klustering) because
  3907.      * we are at a low level munging page table entries ourselves here.
  3908.      */
  3909.     for (page = 0;
  3910.          page < VMMACH_NUM_PAGES_PER_SEG_INT;
  3911.          page++, virtAddr += VMMACH_PAGE_SIZE_INT) {
  3912.         pte = VmMachGetPageMap(virtAddr);
  3913.         if (!(pte & VMMACH_RESIDENT_BIT)) {
  3914.             if (freeVirtAddr == 0) {
  3915.             /*
  3916.              * Note the unused page in this special area of the
  3917.              * kernel virtual address space.
  3918.              */
  3919.             freeVirtAddr = virtAddr;
  3920.         }
  3921.         } else if ((pte & VMMACH_PAGE_FRAME_FIELD) == pageFrame &&
  3922.                VmMachGetPageType(pte) == type) {
  3923.         /*
  3924.          * A page is already mapped for this physical address.
  3925.          */
  3926.         return(virtAddr + ((int)devPhysAddr & VMMACH_OFFSET_MASK_INT));
  3927.         }
  3928.     }
  3929.     }
  3930.  
  3931.     pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT | pageFrame;
  3932. #if defined(sun3) || defined(sun4)    /* Not just for porting purposes */
  3933.     pte |= VMMACH_DONT_CACHE_BIT;
  3934. #endif
  3935.     VmMachSetPageType(pte, type);
  3936.     if (freeVirtAddr != 0) {
  3937.     VmMachSetPageMap(freeVirtAddr, pte);
  3938.     /*
  3939.      * Return the kernel virtual address used to access it.
  3940.      */
  3941.     return(freeVirtAddr + ((int)devPhysAddr & VMMACH_OFFSET_MASK_INT));
  3942.     } else if (freePMEGAddr != 0) {
  3943.     int oldContext;
  3944.     int pmeg;
  3945.     int i;
  3946.  
  3947.     /*
  3948.      * Map in a new PMEG so we can use it for mapping.
  3949.      */
  3950.     pmeg = PMEGGet(vm_SysSegPtr, 
  3951.                (int) ((unsigned)freePMEGAddr >> VMMACH_SEG_SHIFT),
  3952.                PMEG_DONT_ALLOC);
  3953.     oldContext = VmMachGetContextReg();
  3954.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  3955.         VmMachSetContextReg(i);
  3956.         VmMachSetSegMap(freePMEGAddr, pmeg);
  3957.     }
  3958.     VmMachSetContextReg(oldContext);
  3959.     VmMachSetPageMap(freePMEGAddr, pte);
  3960.     return(freePMEGAddr + ((int)devPhysAddr & VMMACH_OFFSET_MASK_INT));
  3961.     } else {
  3962.     return((Address)NIL);
  3963.     }
  3964. }
  3965.  
  3966. /*
  3967.  ----------------------------------------------------------------------
  3968.  *
  3969.  * VmMach_MapInBigDevice --
  3970.  *
  3971.  *    Map a device at some physical address into kernel virtual address.
  3972.  *    This is for use by the controller initialization routines.
  3973.  *    This is suitable for devices that need to map in more than
  3974.  *    one page of contiguous memory.
  3975.  *    The routine sets up the page table so that it references the device.
  3976.  *
  3977.  * Results:
  3978.  *    The kernel virtual address needed to reference the device is returned.
  3979.  *    NIL is returned upon failure.
  3980.  *
  3981.  * Side effects:
  3982.  *    The hardware page table is modified.  This may steal
  3983.  *    pages from kernel virtual space, unless pages can be cleverly re-used.
  3984.  *
  3985.  *----------------------------------------------------------------------
  3986.  */
  3987. Address
  3988. VmMach_MapInBigDevice(devPhysAddr, numBytes, type)
  3989.     Address    devPhysAddr;    /* Physical address of the device to map in. */
  3990.     int        numBytes;    /* Bytes needed by device. */
  3991.     int        type;        /* Value for the page table entry type field.
  3992.                  * This depends on the address space that
  3993.                  * the devices live in, ie. VME D16 or D32. */
  3994. {
  3995.     Address         virtAddr;
  3996.     Address        freeVirtAddr = (Address)0;
  3997.     Address        freePMEGAddr = (Address)0;
  3998.     int            page;
  3999.     int            pageFrame;
  4000.     VmMachPTE        pte;
  4001.     int            numPages;
  4002.     int            i;
  4003.     Boolean        foundPages;
  4004.  
  4005.     /*
  4006.      * Get the page frame for the physical device so we can
  4007.      * compare it against existing pte's.
  4008.      */
  4009. printf("VmMach_MapInBigDevice:devPhysAddr 0x%x, numBytes %d, type %d\n",
  4010. devPhysAddr, numBytes, type);
  4011.     pageFrame = ((unsigned)devPhysAddr >> VMMACH_PAGE_SHIFT_INT)
  4012.     & VMMACH_PAGE_FRAME_FIELD;
  4013.  
  4014.     numPages = (numBytes / VMMACH_PAGE_SIZE_INT) + 1;
  4015.     if (numPages > VMMACH_NUM_PAGES_PER_SEG_INT) {
  4016.     printf("Can only map in one segment's worth of pages right now.\n");
  4017.     return (Address) NIL;
  4018.     }
  4019. printf("numPages is %d\n", numPages);
  4020.     /* For only one pages, just call the old routine. */
  4021.     if (numPages <= 1) {
  4022.     return VmMach_MapInDevice(devPhysAddr, type);
  4023.     }
  4024.  
  4025.     /*
  4026.      * Spin through the segments and their pages looking for a free
  4027.      * page or a virtual page that is already mapped to the physical page.
  4028.      */
  4029.     for (virtAddr = (Address)VMMACH_DEV_START_ADDR;
  4030.          virtAddr < (Address)VMMACH_DEV_END_ADDR; ) {
  4031. printf("Trying virtAddr 0x%x\n", virtAddr);
  4032.     if (VmMachGetSegMap(virtAddr) == VMMACH_INV_PMEG) {
  4033.         /* 
  4034.          * If we can't find any free mappings we can use this PMEG.
  4035.          */
  4036.         if (freePMEGAddr == 0) {
  4037. printf("Got free pmeg.\n");
  4038.         freePMEGAddr = virtAddr;
  4039.         }
  4040.         virtAddr += VMMACH_SEG_SIZE;
  4041.         continue;
  4042.     }
  4043.     /*
  4044.      * Careful, use the correct page size when incrementing virtAddr.
  4045.      * Use the real hardware size (ignore software klustering) because
  4046.      * we are at a low level munging page table entries ourselves here.
  4047.      */
  4048.     foundPages = FALSE;
  4049.     for (page = 0;
  4050.          page < VMMACH_NUM_PAGES_PER_SEG_INT;
  4051.          page++, virtAddr += VMMACH_PAGE_SIZE_INT) {
  4052.  
  4053.         /* Are there enough pages left in the segment? */
  4054.         if (VMMACH_NUM_PAGES_PER_SEG_INT - page < numPages) {
  4055. printf("Only %d pages left - go to next seg.\n", VMMACH_NUM_PAGES_PER_SEG_INT -
  4056. numPages);
  4057.         /* If we just continue, virtAddr will be incremented okay. */
  4058.         continue;
  4059.         }
  4060.  
  4061.         pte = VmMachGetPageMap(virtAddr);
  4062.         if ((pte & VMMACH_RESIDENT_BIT) &&
  4063.         (pte & VMMACH_PAGE_FRAME_FIELD) == pageFrame &&
  4064.                VmMachGetPageType(pte) == type) {
  4065.         /*
  4066.          * A page is already mapped for this physical address.
  4067.          */
  4068.         printf("A page is already mapped for this device!\n");
  4069.         return (Address) NIL;
  4070. #ifdef NOTDEF
  4071.         /*
  4072.          * Instead, we could loop through trying to find all
  4073.          * mapped pages, but I don't think we'll ever find any
  4074.          * for these devices.
  4075.          */
  4076.         return (virtAddr + ((int)devPhysAddr & VMMACH_OFFSET_MASK_INT));
  4077. #endif NOTDEF
  4078.         }
  4079.  
  4080.         if (!(pte & VMMACH_RESIDENT_BIT)) {
  4081.         /*
  4082.          * Note the unused page in this special area of the
  4083.          * kernel virtual address space.
  4084.          */
  4085.         freeVirtAddr = virtAddr;
  4086. printf("Free page # %d at add 0x%x\n", page, virtAddr); 
  4087.  
  4088.         /* See if we have enough other consecutive pages. */
  4089.         for (i = 1; i < numPages; i++) {
  4090.             pte = VmMachGetPageMap(virtAddr +
  4091.                 (i * VMMACH_PAGE_SIZE_INT));
  4092.             /* If this is already taken, give up and continue. */
  4093.             if (pte & VMMACH_RESIDENT_BIT) {
  4094. printf("Oops, page # %d is taken.\n", page + i);
  4095.             /* Maybe I should check if it's this device mapped? */
  4096.             break;
  4097.             }
  4098.         }
  4099.         /* Did we find enough pages? */
  4100.         if (i == numPages) {
  4101.             foundPages = TRUE;
  4102. printf("Found enough pages.\n");
  4103.             break;
  4104.         }
  4105.         /* The address wasn't good. */
  4106.         freeVirtAddr = (Address) 0;
  4107.  
  4108.         /* So that we'll test the right page next time around. */
  4109.         page += i;
  4110.         virtAddr += (i * VMMACH_PAGE_SIZE_INT);
  4111.         }
  4112.     }
  4113.     if (foundPages) {
  4114. printf("Yup, really found pages.\n");
  4115.         break;
  4116.     }
  4117.     }
  4118.  
  4119.     /* Did we find a set of pages? */
  4120.     if (freeVirtAddr != 0) {
  4121.     virtAddr = freeVirtAddr;
  4122. printf("Using pages at addr 0x%x\n", virtAddr);
  4123.     for (i = 0; i < numPages; i++) {
  4124.         pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT | pageFrame;
  4125. #if defined(sun3) || defined(sun4)
  4126.         pte |= VMMACH_DONT_CACHE_BIT;
  4127. #endif
  4128.         VmMachSetPageType(pte, type);
  4129.         VmMachSetPageMap(virtAddr, pte);
  4130.         pageFrame++;
  4131.         virtAddr += VMMACH_PAGE_SIZE_INT;
  4132.     }
  4133.  
  4134.     /*
  4135.      * Return the kernel virtual address used to access it.
  4136.      */
  4137.     return (freeVirtAddr + ((int)devPhysAddr & VMMACH_OFFSET_MASK_INT));
  4138.  
  4139.     /* Or did we find a whole free pmeg? */
  4140.     } else if (freePMEGAddr != 0) {
  4141.     int oldContext;
  4142.     int pmeg;
  4143.  
  4144.     /*
  4145.      * Map in a new PMEG so we can use it for mapping.
  4146.      */
  4147. printf("Found a whole pmeg at 0x%x\n", freePMEGAddr);
  4148.     pmeg = PMEGGet(vm_SysSegPtr, 
  4149.                (int) ((unsigned)freePMEGAddr >> VMMACH_SEG_SHIFT),
  4150.                PMEG_DONT_ALLOC);
  4151.     oldContext = VmMachGetContextReg();
  4152.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  4153.         VmMachSetContextReg(i);
  4154.         VmMachSetSegMap(freePMEGAddr, pmeg);
  4155.     }
  4156.     VmMachSetContextReg(oldContext);
  4157.  
  4158.     virtAddr = freePMEGAddr;
  4159.     for (i = 0; i < numPages; i++) {
  4160.         pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT | pageFrame;
  4161. #if defined(sun3) || defined(sun4)
  4162.         pte |= VMMACH_DONT_CACHE_BIT;
  4163. #endif
  4164.         VmMachSetPageType(pte, type);
  4165.         VmMachSetPageMap(virtAddr, pte);
  4166.         pageFrame++;
  4167.         virtAddr += VMMACH_PAGE_SIZE_INT;
  4168.     }
  4169.  
  4170.     return (freePMEGAddr + ((int)devPhysAddr & VMMACH_OFFSET_MASK_INT));
  4171.  
  4172.     }
  4173.  
  4174.     /* Nothing was found. */
  4175. printf("Found nothing.\n");
  4176.     return (Address) NIL;
  4177. }
  4178.  
  4179.  
  4180. /*----------------------------------------------------------------------
  4181.  *
  4182.  * DevBufferInit --
  4183.  *
  4184.  *    Initialize a range of virtual memory to allocate from out of the
  4185.  *    device memory space.
  4186.  *
  4187.  * Results:
  4188.  *    None.
  4189.  *
  4190.  * Side effects:
  4191.  *    The buffer struct is initialized and the hardware page map is zeroed
  4192.  *    out in the range of addresses.
  4193.  *
  4194.  *----------------------------------------------------------------------
  4195.  */
  4196. INTERNAL static void
  4197. DevBufferInit()
  4198. {
  4199.     Address        virtAddr;
  4200.     unsigned char    pmeg;
  4201.     int            oldContext;
  4202.     int            i;
  4203.     Address    baseAddr;
  4204.     Address    endAddr;
  4205.  
  4206.     /*
  4207.      * Round base up to next page boundary and end down to page boundary.
  4208.      */
  4209.     baseAddr = (Address)VMMACH_DMA_START_ADDR;
  4210.     endAddr = (Address)(VMMACH_DMA_START_ADDR + VMMACH_DMA_SIZE);
  4211.  
  4212.     /* 
  4213.      * Set up the hardware pages tables in the range of addresses given.
  4214.      */
  4215.     for (virtAddr = baseAddr; virtAddr < endAddr; ) {
  4216.     if (VmMachGetSegMap(virtAddr) != VMMACH_INV_PMEG) {
  4217.         printf("DevBufferInit: DMA space already valid at 0x%x\n",
  4218.            (unsigned int) virtAddr);
  4219.     }
  4220.     /* 
  4221.      * Need to allocate a PMEG.
  4222.      */
  4223.     pmeg = PMEGGet(vm_SysSegPtr, 
  4224.                (int) ((unsigned)virtAddr >> VMMACH_SEG_SHIFT),
  4225.                PMEG_DONT_ALLOC);
  4226.     oldContext = VmMachGetContextReg();
  4227.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  4228.         VmMachSetContextReg(i);
  4229.         VmMachSetSegMap(virtAddr, (int)pmeg);
  4230.     }
  4231.     VmMachSetContextReg(oldContext);
  4232.     virtAddr += VMMACH_SEG_SIZE;
  4233.     }
  4234.     return;
  4235. }
  4236.  
  4237.  
  4238. static    Boolean    dmaPageBitMap[VMMACH_DMA_SIZE / VMMACH_PAGE_SIZE_INT];
  4239.  
  4240. static Boolean dmaInitialized = FALSE;
  4241.  
  4242. /*
  4243.  ----------------------------------------------------------------------
  4244.  *
  4245.  * VmMach_DMAAlloc --
  4246.  *
  4247.  *    Allocate a set of virtual pages to a routine for mapping purposes.
  4248.  *    
  4249.  * Results:
  4250.  *    Pointer into kernel virtual address space of where to access the
  4251.  *    memory, or NIL if the request couldn't be satisfied.
  4252.  *
  4253.  * Side effects:
  4254.  *    The hardware page table is modified.
  4255.  *
  4256.  *----------------------------------------------------------------------
  4257.  */
  4258. ENTRY Address
  4259. VmMach_DMAAlloc(numBytes, srcAddr)
  4260.     int        numBytes;        /* Number of bytes to map in. */
  4261.     Address    srcAddr;    /* Kernel virtual address to start mapping in.*/
  4262. {
  4263.     Address    beginAddr;
  4264.     Address    endAddr;
  4265.     int        numPages;
  4266.     int        i, j;
  4267.     VmMachPTE    pte;
  4268.     Boolean    foundIt = FALSE;
  4269.     Address    newAddr;
  4270.  
  4271.     MASTER_LOCK(vmMachMutexPtr);
  4272.     if (!dmaInitialized) {
  4273.     /* Where to allocate the memory from. */
  4274.     dmaInitialized = TRUE;
  4275.     DevBufferInit();
  4276.     }
  4277.  
  4278.     /* calculate number of pages needed */
  4279.                         /* beginning of first page */
  4280.     beginAddr = (Address) (((unsigned int)(srcAddr)) & ~VMMACH_OFFSET_MASK_INT);
  4281.                         /* beginning of last page */
  4282.     endAddr = (Address) ((((unsigned int) srcAddr) + numBytes - 1) &
  4283.         ~VMMACH_OFFSET_MASK_INT);
  4284.     numPages = (((unsigned int) endAddr) >> VMMACH_PAGE_SHIFT_INT) -
  4285.         (((unsigned int) beginAddr) >> VMMACH_PAGE_SHIFT_INT) + 1;
  4286.  
  4287.     /* see if request can be satisfied */
  4288.     for (i = 0; i < (VMMACH_DMA_SIZE / VMMACH_PAGE_SIZE_INT); i++) {
  4289.     if (dmaPageBitMap[i] == 1) {
  4290.         continue;
  4291.     }
  4292.     /*
  4293.      * Must be aligned in the cache to avoid write-backs of stale data
  4294.      * from other references to stuff on this page.
  4295.      */
  4296.     newAddr = (Address)(VMMACH_DMA_START_ADDR + (i * VMMACH_PAGE_SIZE_INT));
  4297.     if (((unsigned int) newAddr & (VMMACH_CACHE_SIZE - 1)) !=
  4298.         ((unsigned int) beginAddr & (VMMACH_CACHE_SIZE - 1))) {
  4299.         continue;
  4300.     }
  4301.     for (j = 1; j < numPages &&
  4302.         ((i + j) < (VMMACH_DMA_SIZE / VMMACH_PAGE_SIZE_INT)); j++) {
  4303.         if (dmaPageBitMap[i + j] == 1) {
  4304.         break;
  4305.         }
  4306.     }
  4307.     if (j == numPages &&
  4308.         ((i + j) < (VMMACH_DMA_SIZE / VMMACH_PAGE_SIZE_INT))) {
  4309.         foundIt = TRUE;
  4310.         break;
  4311.     }
  4312.     }
  4313.     if (!foundIt) {
  4314.     MASTER_UNLOCK(vmMachMutexPtr);
  4315.     panic(
  4316.         "VmMach_DMAAlloc: unable to satisfy request for %d bytes at 0x%x\n",
  4317.         numBytes, srcAddr);
  4318. #ifdef NOTDEF
  4319.     return (Address) NIL;
  4320. #endif NOTDEF
  4321.     }
  4322.     for (j = 0; j < numPages; j++) {
  4323.     dmaPageBitMap[i + j] = 1;    /* allocate page */
  4324.     pte = VmMachGetPageMap(srcAddr);
  4325.     pte |= VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT;
  4326.     VmMachSetPageMap(((i + j) * VMMACH_PAGE_SIZE_INT) +
  4327.         VMMACH_DMA_START_ADDR, pte);
  4328.     srcAddr += VMMACH_PAGE_SIZE_INT;
  4329.     }
  4330.     beginAddr = (Address) (VMMACH_DMA_START_ADDR + (i * VMMACH_PAGE_SIZE_INT) +
  4331.         (((unsigned int) srcAddr) & VMMACH_OFFSET_MASK_INT));
  4332.  
  4333.     MASTER_UNLOCK(vmMachMutexPtr);
  4334.     return beginAddr;
  4335. }
  4336.  
  4337. /*
  4338.  ----------------------------------------------------------------------
  4339.  *
  4340.  * VmMach_DMAAllocContiguous --
  4341.  *
  4342.  *    WARNING:  this routine doesn't work yet!!
  4343.  *    Allocate a set of virtual pages to a routine for mapping purposes.
  4344.  *    
  4345.  * Results:
  4346.  *    Pointer into kernel virtual address space of where to access the
  4347.  *    memory, or NIL if the request couldn't be satisfied.
  4348.  *
  4349.  * Side effects:
  4350.  *    The hardware page table is modified.
  4351.  *
  4352.  *----------------------------------------------------------------------
  4353.  */
  4354. #ifndef sun4c
  4355. ReturnStatus
  4356. VmMach_DMAAllocContiguous(inScatGathPtr, scatGathLength, outScatGathPtr)
  4357.     register Net_ScatterGather    *inScatGathPtr;
  4358.     register int        scatGathLength;
  4359.     register Net_ScatterGather    *outScatGathPtr;
  4360. {
  4361.     Address    beginAddr = 0;
  4362.     Address    endAddr;
  4363.     int        numPages;
  4364.     int        i, j;
  4365.     VmMachPTE    pte;
  4366.     Boolean    foundIt = FALSE;
  4367.     int        virtPage;
  4368.     Net_ScatterGather        *inPtr;
  4369.     Net_ScatterGather        *outPtr;
  4370.     int                pageOffset;
  4371.     Address            srcAddr;
  4372.     Address            newAddr;
  4373.  
  4374.     if (!dmaInitialized) {
  4375.     dmaInitialized = TRUE;
  4376.     DevBufferInit();
  4377.     }
  4378.     /* calculate number of pages needed */
  4379.     inPtr = inScatGathPtr;
  4380.     outPtr = outScatGathPtr;
  4381.     numPages = 0;
  4382.     for (i = 0; i < scatGathLength; i++) {
  4383.     if (inPtr->length > 0) {
  4384.         /* beginning of first page */
  4385.         beginAddr = (Address) (((unsigned int)(inPtr->bufAddr)) & 
  4386.             ~VMMACH_OFFSET_MASK_INT);
  4387.         /* beginning of last page */
  4388.         endAddr = (Address) ((((unsigned int) inPtr->bufAddr) + 
  4389.         inPtr->length - 1) & ~VMMACH_OFFSET_MASK_INT);
  4390.         /* 
  4391.          * Temporarily store the number of pages in the out scatter/gather
  4392.          * array.
  4393.          */
  4394.         outPtr->length =
  4395.             (((unsigned int) endAddr) >> VMMACH_PAGE_SHIFT_INT) -
  4396.             (((unsigned int) beginAddr) >> VMMACH_PAGE_SHIFT_INT) + 1;
  4397.     } else {
  4398.         outPtr->length = 0;
  4399.     }
  4400.     if ((i == 0) && (outPtr->length != 1)) {
  4401.         panic("Help! Help! I'm being repressed!\n");
  4402.     }
  4403.     numPages += outPtr->length;
  4404.     inPtr++;
  4405.     outPtr++;
  4406.     }
  4407.  
  4408.     /* see if request can be satisfied */
  4409.     for (i = 0; i < (VMMACH_DMA_SIZE / VMMACH_PAGE_SIZE_INT); i++) {
  4410.     if (dmaPageBitMap[i] == 1) {
  4411.         continue;
  4412.     }
  4413.     /*
  4414.      * Must be aligned in the cache to avoid write-backs of stale data
  4415.      * from other references to stuff on this page.
  4416.      */
  4417.     newAddr = (Address)(VMMACH_DMA_START_ADDR + (i * VMMACH_PAGE_SIZE_INT));
  4418.     if (((unsigned int) newAddr & (VMMACH_CACHE_SIZE - 1)) !=
  4419.         ((unsigned int) beginAddr & (VMMACH_CACHE_SIZE - 1))) {
  4420.         continue;
  4421.     }
  4422.     for (j = 1; j < numPages &&
  4423.         ((i + j) < (VMMACH_DMA_SIZE / VMMACH_PAGE_SIZE_INT)); j++) {
  4424.         if (dmaPageBitMap[i + j] == 1) {
  4425.         break;
  4426.         }
  4427.     }
  4428.     if (j == numPages &&
  4429.         ((i + j) < (VMMACH_DMA_SIZE / VMMACH_PAGE_SIZE_INT))) {
  4430.         foundIt = TRUE;
  4431.         break;
  4432.     }
  4433.     }
  4434.     if (!foundIt) {
  4435.     return FAILURE;
  4436.     }
  4437.     pageOffset = i;
  4438.     inPtr = inScatGathPtr;
  4439.     outPtr = outScatGathPtr;
  4440.     for (i = 0; i < scatGathLength; i++) {
  4441.     srcAddr = inPtr->bufAddr;
  4442.     numPages = outPtr->length;
  4443.     for (j = 0; j < numPages; j++) {
  4444.         dmaPageBitMap[pageOffset + j] = 1;    /* allocate page */
  4445.         virtPage = ((unsigned int) srcAddr) >> VMMACH_PAGE_SHIFT;
  4446.         pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT |
  4447.           VirtToPhysPage(Vm_GetKernPageFrame(virtPage));
  4448.         SET_ALL_PAGE_MAP(((pageOffset + j) * VMMACH_PAGE_SIZE_INT) +
  4449.             VMMACH_DMA_START_ADDR, pte);
  4450.         srcAddr += VMMACH_PAGE_SIZE;
  4451.     }
  4452.     outPtr->bufAddr = (Address) (VMMACH_DMA_START_ADDR + 
  4453.         (pageOffset * VMMACH_PAGE_SIZE_INT) + 
  4454.         (((unsigned int) srcAddr) & VMMACH_OFFSET_MASK));
  4455.     pageOffset += numPages;
  4456.     outPtr->length = inPtr->length;
  4457.     inPtr++;
  4458.     outPtr++;
  4459.     }
  4460.     return SUCCESS;
  4461. }
  4462. #endif /* sun4c */
  4463.  
  4464.  
  4465. /*
  4466.  ----------------------------------------------------------------------
  4467.  *
  4468.  * VmMach_DMAFree --
  4469.  *
  4470.  *    Free a previously allocated set of virtual pages for a routine that
  4471.  *    used them for mapping purposes.
  4472.  *    
  4473.  * Results:
  4474.  *    None.
  4475.  *
  4476.  * Side effects:
  4477.  *    The hardware page table is modified.
  4478.  *
  4479.  *----------------------------------------------------------------------
  4480.  */
  4481. ENTRY void
  4482. VmMach_DMAFree(numBytes, mapAddr)
  4483.     int        numBytes;        /* Number of bytes to map in. */
  4484.     Address    mapAddr;    /* Kernel virtual address to unmap.*/
  4485. {
  4486.     Address    beginAddr;
  4487.     Address    endAddr;
  4488.     int        numPages;
  4489.     int        i, j;
  4490.  
  4491.     MASTER_LOCK(vmMachMutexPtr);
  4492.     /* calculate number of pages to free */
  4493.                         /* beginning of first page */
  4494.     beginAddr = (Address) (((unsigned int) mapAddr) & ~VMMACH_OFFSET_MASK_INT);
  4495.                         /* beginning of last page */
  4496.     endAddr = (Address) ((((unsigned int) mapAddr) + numBytes - 1) &
  4497.         ~VMMACH_OFFSET_MASK_INT);
  4498.     numPages = (((unsigned int) endAddr) >> VMMACH_PAGE_SHIFT_INT) -
  4499.         (((unsigned int) beginAddr) >> VMMACH_PAGE_SHIFT_INT) + 1;
  4500.  
  4501.     i = (((unsigned int) mapAddr) >> VMMACH_PAGE_SHIFT_INT) -
  4502.     (((unsigned int) VMMACH_DMA_START_ADDR) >> VMMACH_PAGE_SHIFT_INT);
  4503.     for (j = 0; j < numPages; j++) {
  4504.     dmaPageBitMap[i + j] = 0;    /* free page */
  4505.     if (vmMachHasVACache) {
  4506.         VmMachFlushPage(mapAddr);
  4507.     }
  4508.     VmMachSetPageMap(mapAddr, (VmMachPTE) 0);
  4509.     mapAddr += VMMACH_PAGE_SIZE_INT;
  4510.     }
  4511.     MASTER_UNLOCK(vmMachMutexPtr);
  4512.     return;
  4513. }
  4514.  
  4515.  
  4516.  
  4517. /*
  4518.  * ----------------------------------------------------------------------------
  4519.  *
  4520.  * VmMach_MapKernelIntoUser --
  4521.  *
  4522.  *      Map a portion of kernel memory into the user's heap segment.  
  4523.  *    It will only map objects on hardware segment boundaries.  This is 
  4524.  *    intended to be used to map devices such as video memory.
  4525.  *
  4526.  *    NOTE: It is assumed that the user process knows what the hell it is
  4527.  *          doing.
  4528.  *
  4529.  * Results:
  4530.  *      Return the virtual address that it chose to map the memory at.
  4531.  *
  4532.  * Side effects:
  4533.  *      The hardware segment table for the user process's segment is modified
  4534.  *    to map in the addresses.
  4535.  *
  4536.  * ----------------------------------------------------------------------------
  4537.  */
  4538. ReturnStatus
  4539. VmMach_MapKernelIntoUser(kernelVirtAddr, numBytes, userVirtAddr,
  4540.              realVirtAddrPtr) 
  4541.     unsigned int    kernelVirtAddr;        /* Kernel virtual address
  4542.                           * to map in. */
  4543.     int    numBytes;                /* Number of bytes to map. */
  4544.     unsigned int    userVirtAddr;         /* User virtual address to
  4545.                           * attempt to start mapping
  4546.                          * in at. */
  4547.     unsigned int    *realVirtAddrPtr;    /* Where we were able to start
  4548.                           * mapping at. */
  4549. {
  4550.     Address             newUserVirtAddr;
  4551.     ReturnStatus        status;
  4552.  
  4553.     status = VmMach_IntMapKernelIntoUser(kernelVirtAddr, numBytes,
  4554.             userVirtAddr, &newUserVirtAddr);
  4555.  
  4556.     if (status != SUCCESS) {
  4557.         return status;
  4558.     }
  4559.  
  4560.     return Vm_CopyOut(4, (Address) &newUserVirtAddr, (Address) realVirtAddrPtr);
  4561. }
  4562.  
  4563.  
  4564. /*
  4565.  * ----------------------------------------------------------------------------
  4566.  *
  4567.  * Vm_IntMapKernelIntoUser --
  4568.  *
  4569.  *      Map a portion of kernel memory into the user's heap segment.
  4570.  *      It will only map objects on hardware segment boundaries.  This is
  4571.  *      intended to be used to map devices such as video memory.
  4572.  *
  4573.  *      This routine can be called from within the kernel since it doesn't
  4574.  *      do a Vm_CopyOut of the new user virtual address.
  4575.  *
  4576.  *      NOTE: It is assumed that the user process knows what the hell it is
  4577.  *            doing.
  4578.  *
  4579.  * Results:
  4580.  *      SUCCESS or FAILURE status.
  4581.  *      Return the virtual address that it chose to map the memory at in
  4582.  *      an out parameter.
  4583.  *
  4584.  * Side effects:
  4585.  *      The hardware segment table for the user process's segment is modified
  4586.  *      to map in the addresses.
  4587.  *
  4588.  * ----------------------------------------------------------------------------
  4589.  */
  4590. ReturnStatus
  4591. VmMach_IntMapKernelIntoUser(kernelVirtAddr, numBytes, userVirtAddr, newAddrPtr)
  4592.     unsigned int        kernelVirtAddr;         /* Kernel virtual address
  4593.                                                  * to map in. */
  4594.     int numBytes;                               /* Number of bytes to map. */
  4595.     unsigned int        userVirtAddr;           /* User virtual address to
  4596.                                                  * attempt to start mapping
  4597.                                                  * in at. */
  4598.     Address             *newAddrPtr;            /* New user address. */
  4599. {
  4600.     int                         numSegs;
  4601.     int                         firstPage;
  4602.     int                         numPages;
  4603.     Proc_ControlBlock           *procPtr;
  4604.     register    Vm_Segment      *segPtr;
  4605.     int                         hardSegNum;
  4606.     int                         i;
  4607.     unsigned int                pte;
  4608.  
  4609.     procPtr = Proc_GetCurrentProc();
  4610.     segPtr = procPtr->vmPtr->segPtrArray[VM_HEAP];
  4611.  
  4612.     numSegs = numBytes >> VMMACH_SEG_SHIFT;
  4613.     numPages = numSegs * VMMACH_SEG_SIZE / VMMACH_PAGE_SIZE;
  4614.  
  4615.     /*
  4616.      * Make user virtual address hardware segment aligned (round up) and
  4617.      * make sure that there is enough space to map things.
  4618.      */
  4619.     hardSegNum =
  4620.             (unsigned int) (userVirtAddr + VMMACH_SEG_SIZE - 1) >> VMMACH_SEG_SHIFT;
  4621.     userVirtAddr = hardSegNum << VMMACH_SEG_SHIFT;
  4622.     if (hardSegNum + numSegs > VMMACH_NUM_SEGS_PER_CONTEXT) {
  4623.         return(SYS_INVALID_ARG);
  4624.     }
  4625.  
  4626.     /*
  4627.      * Make sure will fit into the kernel's VAS.  Assume that is hardware
  4628.      * segment aligned.
  4629.      */
  4630.     hardSegNum = (unsigned int) (kernelVirtAddr) >> VMMACH_SEG_SHIFT;
  4631.     if (hardSegNum + numSegs > VMMACH_NUM_SEGS_PER_CONTEXT) {
  4632.         return(SYS_INVALID_ARG);
  4633.     }
  4634.  
  4635.     /*
  4636.      * Invalidate all virtual memory for the heap segment of this process
  4637.      * in the given range of virtual addresses that we are to map.  This
  4638.      * assures us that there aren't any hardware pages allocated for this
  4639.      * segment in this range of addresses.
  4640.      */
  4641.     firstPage = (unsigned int) (userVirtAddr) >> VMMACH_PAGE_SHIFT;
  4642.     (void)Vm_DeleteFromSeg(segPtr, firstPage, firstPage + numPages - 1);
  4643.  
  4644.     /*
  4645.      * Now go into the kernel's hardware segment table and copy the
  4646.      * segment table entries into the heap segments hardware segment table.
  4647.      */
  4648.  
  4649.     bcopy((Address)GetHardSegPtr(vm_SysSegPtr->machPtr, hardSegNum),
  4650.         (Address)GetHardSegPtr(segPtr->machPtr,
  4651.                 (unsigned int)userVirtAddr >> VMMACH_SEG_SHIFT),
  4652.                 numSegs * sizeof (VMMACH_SEG_NUM));
  4653.     for (i = 0; i < numSegs * VMMACH_NUM_PAGES_PER_SEG_INT; i++) {
  4654.         pte = VmMachGetPageMap((Address)(kernelVirtAddr +
  4655.                 (i * VMMACH_PAGE_SIZE_INT)));
  4656.         pte &= ~VMMACH_KR_PROT;
  4657.         pte |= VMMACH_URW_PROT;
  4658.         VmMachSetPageMap((Address)(kernelVirtAddr + (i*VMMACH_PAGE_SIZE_INT)),
  4659.                 pte);
  4660.     }
  4661.  
  4662.     /*
  4663.      * Make sure this process never migrates.
  4664.      */
  4665.     Proc_NeverMigrate(procPtr);
  4666.  
  4667.     /*
  4668.      * Reinitialize this process's context using the new segment table.
  4669.      */
  4670.     VmMach_ReinitContext(procPtr);
  4671.  
  4672.     *newAddrPtr = (Address) userVirtAddr;
  4673.     return SUCCESS;
  4674. }
  4675.  
  4676.  
  4677. /*
  4678.  *----------------------------------------------------------------------
  4679.  *
  4680.  * VmMach_FlushPage --
  4681.  *
  4682.  *    Flush the page at the given virtual address from all caches.  We
  4683.  *    don't have to do anything on the Sun-2 and Sun-3 workstations
  4684.  *    that we have.
  4685.  *
  4686.  * Results:
  4687.  *    None.
  4688.  *
  4689.  * Side effects:
  4690.  *    The given page is flushed from the caches.
  4691.  *
  4692.  *----------------------------------------------------------------------
  4693.  */
  4694. /*ARGSUSED*/
  4695. void
  4696. VmMach_FlushPage(virtAddrPtr, invalidate)
  4697.     Vm_VirtAddr    *virtAddrPtr;
  4698.     Boolean    invalidate;    /* Should invalidate the pte after flushing. */
  4699. {
  4700.     Address    virtAddr;
  4701.     int        i;
  4702.  
  4703.     /* on sun4, ignore invalidate parameter? */
  4704.     virtAddr = (Address) (virtAddrPtr->page << VMMACH_PAGE_SHIFT);
  4705.     if (vmMachHasVACache) {
  4706.     for (i = 0; i < VMMACH_CLUSTER_SIZE; ++i) {
  4707.         VmMachFlushPage(virtAddr + i * VMMACH_PAGE_SIZE_INT);
  4708.     }
  4709.     }
  4710.     if (invalidate) {
  4711.     SET_ALL_PAGE_MAP(virtAddr, (VmMachPTE)0);
  4712.     }
  4713.     return;
  4714. }
  4715.  
  4716.  
  4717. /*
  4718.  *----------------------------------------------------------------------
  4719.  *
  4720.  * VmMach_SetProtForDbg --
  4721.  *
  4722.  *    Set the protection of the kernel pages for the debugger.
  4723.  *
  4724.  * Results:
  4725.  *    None.
  4726.  *
  4727.  * Side effects:
  4728.  *    The protection is set for the given range of kernel addresses.
  4729.  *
  4730.  *----------------------------------------------------------------------
  4731.  */
  4732. void
  4733. VmMach_SetProtForDbg(readWrite, numBytes, addr)
  4734.     Boolean    readWrite;    /* TRUE if should make pages writable, FALSE
  4735.                  * if should make read-only. */
  4736.     int        numBytes;    /* Number of bytes to change protection for. */
  4737.     Address    addr;        /* Address to start changing protection at. */
  4738. {
  4739.     register    Address        virtAddr;
  4740.     register    VmMachPTE     pte;
  4741.     register    int        firstPage;
  4742.     register    int        lastPage;
  4743.     int        oldContext;
  4744.     int        i;
  4745.  
  4746.     /*
  4747.      * This should only be called with kernel text pages so we modify the
  4748.      * PTE for the address in all the contexts. Note that we must flush
  4749.      * the page from the change before changing the protections to avoid
  4750.      * write back errors.
  4751.      */
  4752.     oldContext = VmMachGetContextReg();
  4753.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  4754.     VmMachSetContextReg(i);
  4755.     firstPage = (unsigned)addr >> VMMACH_PAGE_SHIFT_INT;
  4756.     lastPage = ((unsigned)addr + numBytes - 1) >> VMMACH_PAGE_SHIFT_INT;
  4757.     for (; firstPage <= lastPage; firstPage++) {
  4758.         virtAddr = (Address) (firstPage << VMMACH_PAGE_SHIFT_INT);
  4759.         pte = VmMachGetPageMap(virtAddr);
  4760.         pte &= ~VMMACH_PROTECTION_FIELD;
  4761.         pte |= readWrite ? VMMACH_KRW_PROT : VMMACH_KR_PROT;
  4762.         if (vmMachHasVACache) {
  4763.         VmMachFlushPage(virtAddr);
  4764.         }
  4765.         VmMachSetPageMap(virtAddr, pte);
  4766.     }
  4767.     }
  4768.     VmMachSetContextReg(oldContext);
  4769.     return;
  4770. }
  4771.  
  4772.  
  4773. /*
  4774.  *----------------------------------------------------------------------
  4775.  *
  4776.  * VmMach_Cmd --
  4777.  *
  4778.  *    Machine dependent vm commands.
  4779.  *
  4780.  * Results:
  4781.  *    None.
  4782.  *
  4783.  * Side effects:
  4784.  *    None.
  4785.  *
  4786.  *----------------------------------------------------------------------
  4787.  */
  4788. /*ARGSUSED*/
  4789. ReturnStatus
  4790. VmMach_Cmd(command, arg)
  4791.     int    command;
  4792.     int arg;
  4793. {
  4794.     switch (command & 0xf) {
  4795.     case 0:
  4796.     if (vmMachHasVACache) {
  4797.         VmMach_FlushCurrentContext();
  4798.     }
  4799.     break;
  4800.     case 1:
  4801.     if (vmMachHasVACache) {
  4802.         VmMachFlushSegment((Address)arg);
  4803.     }
  4804.     break;
  4805.     case 2:
  4806.     if (vmMachHasVACache) {
  4807.         VmMachFlushPage((Address)arg);
  4808.     }
  4809.     break;
  4810.     case 3:
  4811.     VmMachDoNothing((Address)arg);
  4812.     break;
  4813.     case 4:
  4814.     vmMachHasHwFlush = arg;
  4815.     break;
  4816.     default:
  4817.     return GEN_INVALID_ARG;
  4818.     }
  4819.     return SUCCESS;
  4820.  
  4821. }
  4822.  
  4823. VmMachDoNothing(arg)
  4824. int arg;
  4825. {
  4826. }
  4827.  
  4828.  
  4829. /*
  4830.  *----------------------------------------------------------------------
  4831.  *
  4832.  * VmMach_HandleSegMigration --
  4833.  *
  4834.  *    Do machine-dependent aspects of segment migration.  On the sun4's,
  4835.  *    this means flush the segment from the virtually addressed cache.
  4836.  *
  4837.  * Results:
  4838.  *    None.
  4839.  *
  4840.  * Side effects:
  4841.  *    None.
  4842.  *
  4843.  *----------------------------------------------------------------------
  4844.  */
  4845. void
  4846. VmMach_HandleSegMigration(segPtr)
  4847.     Vm_Segment        *segPtr;    /* Pointer to segment to be migrated. */
  4848. {
  4849.     Address    virtAddr;
  4850.  
  4851.     if (vmMachHasVACache) {
  4852.     virtAddr = (Address) (segPtr->offset << VMMACH_PAGE_SHIFT);
  4853.     VmMachFlushSegment(virtAddr);
  4854.     }
  4855.  
  4856.     return;
  4857. }
  4858.  
  4859.  
  4860. /*
  4861.  *----------------------------------------------------------------------
  4862.  *
  4863.  * VmMach_FlushCode --
  4864.  *
  4865.  *      Does nothing on this machine.
  4866.  *
  4867.  * Results:
  4868.  *      None.
  4869.  *
  4870.  * Side effects:
  4871.  *      None.
  4872.  *
  4873.  *----------------------------------------------------------------------
  4874.  */
  4875. /*ARGSUSED*/
  4876. void
  4877. VmMach_FlushCode(procPtr, virtAddrPtr, virtPage, numBytes)
  4878.     Proc_ControlBlock   *procPtr;
  4879.     Vm_VirtAddr         *virtAddrPtr;
  4880.     unsigned            virtPage;
  4881.     int                 numBytes;
  4882. {
  4883. }
  4884.  
  4885.  
  4886. /*
  4887.  * Dummy function which will turn out to be the function that the debugger
  4888.  * prints out on a backtrace after a trap.  The debugger gets confused
  4889.  * because trap stacks originate from assembly language stacks.  I decided
  4890.  * to make a dummy procedure because it was to confusing seeing the
  4891.  * previous procedure (VmMach_MapKernelIntoUser) on every backtrace.
  4892.  */
  4893. static void
  4894. VmMachTrap()
  4895. {
  4896. }
  4897.  
  4898. #ifndef sun4c
  4899.  
  4900. /*----------------------------------------------------------------------
  4901.  *
  4902.  * Dev32BitBufferInit --
  4903.  *
  4904.  *    Initialize a range of virtual memory to allocate from out of the
  4905.  *    device memory space.
  4906.  *
  4907.  * Results:
  4908.  *    None.
  4909.  *
  4910.  * Side effects:
  4911.  *    The buffer struct is initialized and the hardware page map is zeroed
  4912.  *    out in the range of addresses.
  4913.  *
  4914.  *----------------------------------------------------------------------
  4915.  */
  4916. INTERNAL static void
  4917. Dev32BitDMABufferInit()
  4918. {
  4919.     Address        virtAddr;
  4920.     unsigned char    pmeg;
  4921.     int            oldContext;
  4922.     Address    baseAddr;
  4923.     Address    endAddr;
  4924.  
  4925.     if ((VMMACH_32BIT_DMA_SIZE & (VMMACH_CACHE_SIZE - 1)) != 0) {
  4926.     panic(
  4927. "Dev32BitDMABufferInit: 32-bit DMA area must be a multiple of cache size.\n");
  4928.     }
  4929.  
  4930.     VmMachSetup32BitDVMA(); 
  4931.     /*
  4932.      * Round base up to next page boundary and end down to page boundary.
  4933.      */
  4934.     baseAddr = (Address)VMMACH_32BIT_DMA_START_ADDR;
  4935.     endAddr = (Address)(VMMACH_32BIT_DMA_START_ADDR + VMMACH_32BIT_DMA_SIZE);
  4936.  
  4937.     /* 
  4938.      * Set up the hardware pages tables in the range of addresses given.
  4939.      */
  4940.     oldContext = VmMachGetContextReg();
  4941.     VmMachSetContextReg(0);
  4942.     for (virtAddr = baseAddr; virtAddr < endAddr; ) {
  4943.     if (VmMachGetSegMap(virtAddr) != VMMACH_INV_PMEG) {
  4944.         printf("Dev32BitDMABufferInit: DMA space already valid at 0x%x\n",
  4945.            (unsigned int) virtAddr);
  4946.     }
  4947.     /* 
  4948.      * Need to allocate a PMEG.
  4949.      */
  4950.     pmeg = PMEGGet(vm_SysSegPtr, 
  4951.                (int) ((unsigned)virtAddr >> VMMACH_SEG_SHIFT),
  4952.                PMEG_DONT_ALLOC);
  4953.     if (pmeg == VMMACH_INV_PMEG) {
  4954.         panic("Dev32BitDMABufferInit: unable to get a pmeg.\n");
  4955.     }
  4956.         VmMachSetSegMap(virtAddr, (int)pmeg);
  4957.     virtAddr += VMMACH_SEG_SIZE;
  4958.     }
  4959.     VmMachSetContextReg(oldContext);
  4960. }
  4961.  
  4962.  
  4963. static    Boolean    userdmaPageBitMap[VMMACH_32BIT_DMA_SIZE / VMMACH_PAGE_SIZE_INT];
  4964.  
  4965.  
  4966. /*
  4967.  ----------------------------------------------------------------------
  4968.  *
  4969.  * VmMach_32BitDMAAlloc --
  4970.  *
  4971.  *    Allocate a set of virtual pages to a routine for mapping purposes.
  4972.  *    
  4973.  * Results:
  4974.  *    Pointer into kernel virtual address space of where to access the
  4975.  *    memory, or NIL if the request couldn't be satisfied.
  4976.  *
  4977.  * Side effects:
  4978.  *    The hardware page table is modified.
  4979.  *
  4980.  *----------------------------------------------------------------------
  4981.  */
  4982. ENTRY Address
  4983. VmMach_32BitDMAAlloc(numBytes, srcAddr)
  4984.     int        numBytes;        /* Number of bytes to map in. */
  4985.     Address    srcAddr;    /* Kernel virtual address to start mapping in.*/
  4986. {
  4987.     Address    beginAddr;
  4988.     Address    endAddr;
  4989.     int        numPages;
  4990.     int        i, j;
  4991.     VmMachPTE    pte;
  4992.     Boolean    foundIt = FALSE;
  4993.     static initialized = FALSE;
  4994.     unsigned    oldContext;
  4995.     int        align;
  4996.  
  4997.     MASTER_LOCK(vmMachMutexPtr);
  4998.     if (!initialized) {
  4999.     initialized = TRUE;
  5000.     Dev32BitDMABufferInit();
  5001.     }
  5002.  
  5003.     /* calculate number of pages needed */
  5004.                         /* beginning of first page */
  5005.     beginAddr = (Address) (((unsigned int)(srcAddr)) & ~VMMACH_OFFSET_MASK_INT);
  5006.                         /* beginning of last page */
  5007.     endAddr = (Address) ((((unsigned int) srcAddr) + numBytes - 1) &
  5008.         ~VMMACH_OFFSET_MASK_INT);
  5009.     numPages = (((unsigned int) endAddr) >> VMMACH_PAGE_SHIFT_INT) -
  5010.         (((unsigned int) beginAddr) >> VMMACH_PAGE_SHIFT_INT) + 1;
  5011.  
  5012.     /* set first addr to first entry that is also cache aligned */
  5013.     align = (unsigned int) beginAddr & (VMMACH_CACHE_SIZE - 1);
  5014.     align -= (unsigned int) VMMACH_32BIT_DMA_START_ADDR &
  5015.         (VMMACH_CACHE_SIZE - 1);
  5016.     if ((int) align < 0) {
  5017.     align += VMMACH_CACHE_SIZE;
  5018.     }
  5019.     /* see if request can be satisfied, incrementing by cache size in loop */
  5020.     for (i = align / VMMACH_PAGE_SIZE_INT;
  5021.         i < (VMMACH_32BIT_DMA_SIZE / VMMACH_PAGE_SIZE_INT);
  5022.         i += (VMMACH_CACHE_SIZE / VMMACH_PAGE_SIZE_INT)) {
  5023.     if (userdmaPageBitMap[i] == 1) {
  5024.         continue;
  5025.     }
  5026.     for (j = 1; (j < numPages) &&
  5027.         ((i + j) < (VMMACH_32BIT_DMA_SIZE / VMMACH_PAGE_SIZE_INT));
  5028.         j++) {
  5029.         if (userdmaPageBitMap[i + j] == 1) {
  5030.         break;
  5031.         }
  5032.     }
  5033.     if ((j == numPages) &&
  5034.         ((i + j) < (VMMACH_32BIT_DMA_SIZE / VMMACH_PAGE_SIZE_INT))) {
  5035.         foundIt = TRUE;
  5036.         break;
  5037.     }
  5038.     }
  5039.  
  5040.     if (!foundIt) {
  5041.     MASTER_UNLOCK(vmMachMutexPtr);
  5042.     panic(
  5043.     "VmMach_32BitDMAAlloc: unable to satisfy request for %d bytes at 0x%x\n",
  5044.         numBytes, srcAddr);
  5045. #ifdef NOTDEF
  5046.     return (Address) NIL;
  5047. #endif NOTDEF
  5048.     }
  5049.     oldContext = VmMachGetContextReg();
  5050.     VmMachSetContextReg(0);
  5051.     for (j = 0; j < numPages; j++) {
  5052.     userdmaPageBitMap[i + j] = 1;    /* allocate page */
  5053.     pte = VmMachGetPageMap(srcAddr);
  5054.     pte = (pte & ~VMMACH_PROTECTION_FIELD) | VMMACH_RESIDENT_BIT | 
  5055.             VMMACH_URW_PROT;
  5056.  
  5057.     SET_ALL_PAGE_MAP(((i + j) * VMMACH_PAGE_SIZE_INT) +
  5058.         VMMACH_32BIT_DMA_START_ADDR, pte);
  5059.     srcAddr += VMMACH_PAGE_SIZE;
  5060.     }
  5061.     VmMachSetContextReg((int)oldContext);
  5062.     beginAddr = (Address) (VMMACH_32BIT_DMA_START_ADDR +
  5063.         (i * VMMACH_PAGE_SIZE_INT) +
  5064.         (((unsigned int) srcAddr) & VMMACH_OFFSET_MASK));
  5065.  
  5066.     /* set high VME addr bit */
  5067.     beginAddr = (Address)((unsigned) beginAddr | VMMACH_VME_ADDR_BIT);
  5068.     MASTER_UNLOCK(vmMachMutexPtr);
  5069.     return (Address) beginAddr;
  5070. }
  5071.  
  5072.  
  5073. /*
  5074.  ----------------------------------------------------------------------
  5075.  *
  5076.  * VmMach_32BitDMAFree --
  5077.  *
  5078.  *    Free a previously allocated set of virtual pages for a routine that
  5079.  *    used them for mapping purposes.
  5080.  *    
  5081.  * Results:
  5082.  *    None.
  5083.  *
  5084.  * Side effects:
  5085.  *    The hardware page table is modified.
  5086.  *
  5087.  *----------------------------------------------------------------------
  5088.  */
  5089. ENTRY void
  5090. VmMach_32BitDMAFree(numBytes, mapAddr)
  5091.     int        numBytes;        /* Number of bytes to map in. */
  5092.     Address    mapAddr;    /* Kernel virtual address to unmap.*/
  5093. {
  5094.     Address    beginAddr;
  5095.     Address    endAddr;
  5096.     int        numPages;
  5097.     int        i, j;
  5098.     int         oldContext;
  5099.  
  5100.     MASTER_LOCK(vmMachMutexPtr);
  5101.     /* calculate number of pages to free */
  5102.     /* Clear the VME high bit from the address */
  5103.     mapAddr = (Address) ((unsigned)mapAddr & ~VMMACH_VME_ADDR_BIT);
  5104.                         /* beginning of first page */
  5105.     beginAddr = (Address) (((unsigned int) mapAddr) & ~VMMACH_OFFSET_MASK_INT);
  5106.                         /* beginning of last page */
  5107.     endAddr = (Address) ((((unsigned int) mapAddr) + numBytes - 1) &
  5108.         ~VMMACH_OFFSET_MASK_INT);
  5109.     numPages = (((unsigned int) endAddr) >> VMMACH_PAGE_SHIFT_INT) -
  5110.         (((unsigned int) beginAddr) >> VMMACH_PAGE_SHIFT_INT) + 1;
  5111.  
  5112.     i = (((unsigned int) mapAddr) >> VMMACH_PAGE_SHIFT_INT) -
  5113.     (((unsigned int) VMMACH_32BIT_DMA_START_ADDR) >> VMMACH_PAGE_SHIFT_INT);
  5114.     oldContext = VmMachGetContextReg();
  5115.     VmMachSetContextReg(0);
  5116.     for (j = 0; j < numPages; j++) {
  5117.     userdmaPageBitMap[i + j] = 0;    /* free page */
  5118.     if (vmMachHasVACache) {
  5119.         VmMachFlushPage(mapAddr);
  5120.     }
  5121.     SET_ALL_PAGE_MAP(mapAddr, (VmMachPTE) 0);
  5122.     mapAddr = (Address)((unsigned int) mapAddr + VMMACH_PAGE_SIZE_INT);
  5123.     }
  5124.     VmMachSetContextReg(oldContext);
  5125.     MASTER_UNLOCK(vmMachMutexPtr);
  5126.     return;
  5127. }
  5128.  
  5129. #endif /* not sun4c */
  5130.  
  5131.  
  5132. #define CHECK(x) (((x)<0||(x)>=VMMACH_SHARED_NUM_BLOCKS)?\
  5133.     (panic("Alloc out of bounds"),0):0)
  5134. #define ALLOC(x,s)    (CHECK(x),sharedData->allocVector[(x)]=s)
  5135. #define FREE(x)        (CHECK(x),sharedData->allocVector[(x)]=0)
  5136. #define SIZE(x)        (CHECK(x),sharedData->allocVector[(x)])
  5137. #define ISFREE(x)    (CHECK(x),sharedData->allocVector[(x)]==0)
  5138.  
  5139.  
  5140.  
  5141. /*
  5142.  * ----------------------------------------------------------------------------
  5143.  *
  5144.  * VmMach_Alloc --
  5145.  *
  5146.  *      Allocates a region of shared memory;
  5147.  *
  5148.  * Results:
  5149.  *      SUCCESS if the region can be allocated.
  5150.  *    The starting address is returned in addr.
  5151.  *
  5152.  * Side effects:
  5153.  *      The allocation vector is updated.
  5154.  *
  5155.  * ----------------------------------------------------------------------------
  5156.  */
  5157. static ReturnStatus
  5158. VmMach_Alloc(sharedData, regionSize, addr)
  5159.     VmMach_SharedData    *sharedData;    /* Pointer to shared memory info.  */
  5160.     int            regionSize;    /* Size of region to allocate. */
  5161.     Address        *addr;        /* Address of region. */
  5162. {
  5163.     int numBlocks = (regionSize+VMMACH_SHARED_BLOCK_SIZE-1) /
  5164.         VMMACH_SHARED_BLOCK_SIZE;
  5165.     int i, blockCount, firstBlock;
  5166.  
  5167.     if (sharedData->allocVector == (int *)NULL || sharedData->allocVector ==
  5168.         (int *)NIL) {
  5169.     dprintf("VmMach_Alloc: allocVector uninitialized!\n");
  5170.     }
  5171.  
  5172.     /*
  5173.      * Loop through the alloc vector until we find numBlocks free blocks
  5174.      * consecutively.
  5175.      */
  5176.     blockCount = 0;
  5177.     for (i=sharedData->allocFirstFree;
  5178.         i<=VMMACH_SHARED_NUM_BLOCKS-1 && blockCount<numBlocks;i++) {
  5179.     if (ISFREE(i)) {
  5180.         blockCount++;
  5181.     } else {
  5182.         blockCount = 0;
  5183.         if (i==sharedData->allocFirstFree) {
  5184.         sharedData->allocFirstFree++;
  5185.         }
  5186.     }
  5187.     }
  5188.     if (blockCount < numBlocks) {
  5189.     dprintf("VmMach_Alloc: got %d blocks of %d of %d total\n",
  5190.         blockCount,numBlocks,VMMACH_SHARED_NUM_BLOCKS);
  5191.     return VM_NO_SEGMENTS;
  5192.     }
  5193.     firstBlock = i-blockCount;
  5194.     if (firstBlock == sharedData->allocFirstFree) {
  5195.     sharedData->allocFirstFree += blockCount;
  5196.     }
  5197.     *addr = (Address)(firstBlock*VMMACH_SHARED_BLOCK_SIZE +
  5198.         VMMACH_SHARED_START_ADDR);
  5199.     for (i = firstBlock; i<firstBlock+numBlocks; i++) {
  5200.     ALLOC(i,numBlocks);
  5201.     }
  5202.     dprintf("VmMach_Alloc: got %d blocks at %d (%x)\n",
  5203.         numBlocks,firstBlock,*addr);
  5204.     return SUCCESS;
  5205. }
  5206.  
  5207.  
  5208. /*
  5209.  * ----------------------------------------------------------------------------
  5210.  *
  5211.  * VmMach_Unalloc --
  5212.  *
  5213.  *      Frees a region of shared address space.
  5214.  *
  5215.  * Results:
  5216.  *      None.
  5217.  *
  5218.  * Side effects:
  5219.  *      The allocation vector is updated.
  5220.  *
  5221.  * ----------------------------------------------------------------------------
  5222.  */
  5223.  
  5224. static void
  5225. VmMach_Unalloc(sharedData, addr)
  5226.     VmMach_SharedData    *sharedData;    /* Pointer to shared memory info. */
  5227.     Address    addr;        /* Address of region. */
  5228. {
  5229.     int firstBlock = ((int)addr-VMMACH_SHARED_START_ADDR) /
  5230.         VMMACH_SHARED_BLOCK_SIZE;
  5231.     int numBlocks;
  5232.     int i;
  5233.  
  5234.     if (firstBlock<0 || firstBlock>=VMMACH_SHARED_NUM_BLOCKS) {
  5235.     if (debugVmStubs) {
  5236.         printf("VmMach_Unalloc: addr %x out of range\n", addr);
  5237.     }
  5238.     return;
  5239.     }
  5240.  
  5241.     numBlocks = SIZE(firstBlock);
  5242.  
  5243.     dprintf("VmMach_Unalloc: freeing %d blocks at %x\n",numBlocks,addr);
  5244.     if (firstBlock < sharedData->allocFirstFree) {
  5245.     sharedData->allocFirstFree = firstBlock;
  5246.     }
  5247.     for (i=0;i<numBlocks;i++) {
  5248.     if (ISFREE(i+firstBlock)) {
  5249.         if (debugVmStubs) {
  5250.         printf("Freeing free shared address %d %d %x\n",i,i+firstBlock,
  5251.             (int)addr);
  5252.         }
  5253.         return;
  5254.     }
  5255.     FREE(i+firstBlock);
  5256.     }
  5257. }
  5258.  
  5259. /*
  5260.  * ----------------------------------------------------------------------------
  5261.  *
  5262.  * VmMach_SharedStartAddr --
  5263.  *
  5264.  *      Determine the starting address for a shared segment.
  5265.  *
  5266.  * Results:
  5267.  *      Returns the proper start address for the segment.
  5268.  *
  5269.  * Side effects:
  5270.  *      Allocates part of the shared address space.
  5271.  *
  5272.  * ----------------------------------------------------------------------------
  5273.  */
  5274. /*ARGSUSED*/
  5275. ReturnStatus
  5276. VmMach_SharedStartAddr(procPtr,size,reqAddr, fixed)
  5277.     Proc_ControlBlock    *procPtr;
  5278.     int             size;           /* Length of shared segment. */
  5279.     Address         *reqAddr;        /* Requested start address. */
  5280.     int            fixed;        /* 1 if fixed address requested. */
  5281. {
  5282.     int numBlocks = (size+VMMACH_SHARED_BLOCK_SIZE-1) /
  5283.         VMMACH_SHARED_BLOCK_SIZE;
  5284.     int firstBlock = (((int)*reqAddr)-VMMACH_SHARED_START_ADDR) /
  5285.         VMMACH_SHARED_BLOCK_SIZE;
  5286.     int i;
  5287.     VmMach_SharedData    *sharedData = &procPtr->vmPtr->machPtr->sharedData;
  5288.  
  5289.     if (fixed==0) {
  5290.     return VmMach_Alloc(sharedData, size, reqAddr);
  5291.     } else {
  5292.     for (i = firstBlock; i<firstBlock+numBlocks; i++) {
  5293.         if (i>0) {
  5294.         ALLOC(i,numBlocks);
  5295.         }
  5296.     }
  5297.     return SUCCESS;
  5298.     }
  5299. }
  5300.  
  5301. /*
  5302.  * ----------------------------------------------------------------------------
  5303.  *
  5304.  * VmMach_SharedProcStart --
  5305.  *
  5306.  *      Perform machine dependent initialization of shared memory
  5307.  *    for this process.
  5308.  *
  5309.  * Results:
  5310.  *      None.
  5311.  *
  5312.  * Side effects:
  5313.  *      The storage allocation structures are initialized.
  5314.  *
  5315.  * ----------------------------------------------------------------------------
  5316.  */
  5317. void
  5318. VmMach_SharedProcStart(procPtr)
  5319.     Proc_ControlBlock    *procPtr;
  5320. {
  5321.     VmMach_SharedData    *sharedData = &procPtr->vmPtr->machPtr->sharedData;
  5322.     dprintf("VmMach_SharedProcStart: initializing proc's allocVector\n");
  5323.     if (sharedData->allocVector != (int *)NIL) {
  5324.     panic("VmMach_SharedProcStart: allocVector not NIL\n");
  5325.     }
  5326.     sharedData->allocVector =
  5327.         (int *)malloc(VMMACH_SHARED_NUM_BLOCKS*sizeof(int));
  5328.     if (debugVmStubs) {
  5329.     printf("Initializing allocVector for %x to %x\n", procPtr->processID,
  5330.         sharedData->allocVector);
  5331.     }
  5332.     sharedData->allocFirstFree = 0;
  5333.     bzero((Address) sharedData->allocVector, VMMACH_SHARED_NUM_BLOCKS*
  5334.         sizeof(int));
  5335.     procPtr->vmPtr->sharedStart = (Address) 0x00000000;
  5336.     procPtr->vmPtr->sharedEnd = (Address) 0xffff0000;
  5337. }
  5338.  
  5339. /*
  5340.  * ----------------------------------------------------------------------------
  5341.  *
  5342.  * VmMach_SharedSegFinish --
  5343.  *
  5344.  *      Perform machine dependent cleanup of shared memory
  5345.  *    for this segment.
  5346.  *
  5347.  * Results:
  5348.  *      None.
  5349.  *
  5350.  * Side effects:
  5351.  *      The storage allocation structures are freed.
  5352.  *
  5353.  * ----------------------------------------------------------------------------
  5354.  */
  5355. void
  5356. VmMach_SharedSegFinish(procPtr,addr)
  5357.     Proc_ControlBlock    *procPtr;
  5358.     Address        addr;
  5359. {
  5360.     VmMach_Unalloc(&procPtr->vmPtr->machPtr->sharedData,addr);
  5361. }
  5362.  
  5363. /*
  5364.  * ----------------------------------------------------------------------------
  5365.  *
  5366.  * VmMach_SharedProcFinish --
  5367.  *
  5368.  *      Perform machine dependent cleanup of shared memory
  5369.  *    for this process.
  5370.  *
  5371.  * Results:
  5372.  *      None.
  5373.  *
  5374.  * Side effects:
  5375.  *      The storage allocation structures are freed.
  5376.  *
  5377.  * ----------------------------------------------------------------------------
  5378.  */
  5379. void
  5380. VmMach_SharedProcFinish(procPtr)
  5381.     Proc_ControlBlock    *procPtr;
  5382. {
  5383.     dprintf("VmMach_SharedProcFinish: freeing process's allocVector\n");
  5384.     if (debugVmStubs) {
  5385.     printf("VmMach_SharedProcFinish: freeing process's allocVector %x\n",
  5386.         procPtr->vmPtr->machPtr->sharedData.allocVector);
  5387.     }
  5388.     free((Address)procPtr->vmPtr->machPtr->sharedData.allocVector);
  5389.     procPtr->vmPtr->machPtr->sharedData.allocVector = (int *)NIL;
  5390. }
  5391.  
  5392. /*
  5393.  * ----------------------------------------------------------------------------
  5394.  *
  5395.  * VmMach_CopySharedMem --
  5396.  *
  5397.  *      Copies machine-dependent shared memory data structures to handle
  5398.  *      a fork.
  5399.  *
  5400.  * Results:
  5401.  *      None.
  5402.  *
  5403.  * Side effects:
  5404.  *      The new process gets a copy of the shared memory structures.
  5405.  *
  5406.  * ----------------------------------------------------------------------------
  5407.  */
  5408. void
  5409. VmMach_CopySharedMem(parentProcPtr, childProcPtr)
  5410.     Proc_ControlBlock   *parentProcPtr; /* Parent process. */
  5411.     Proc_ControlBlock   *childProcPtr;  /* Child process. */
  5412. {
  5413.     VmMach_SharedData   *childSharedData =
  5414.             &childProcPtr->vmPtr->machPtr->sharedData;
  5415.     VmMach_SharedData   *parentSharedData =
  5416.             &parentProcPtr->vmPtr->machPtr->sharedData;
  5417.  
  5418.     VmMach_SharedProcStart(childProcPtr);
  5419.  
  5420.     bcopy((Address)parentSharedData->allocVector,
  5421.         (Address)childSharedData->allocVector,
  5422.             VMMACH_SHARED_NUM_BLOCKS*sizeof(int));
  5423.     childSharedData->allocFirstFree = parentSharedData->allocFirstFree;
  5424. }
  5425.  
  5426. /*
  5427.  * ----------------------------------------------------------------------------
  5428.  *
  5429.  * VmMach_LockCachePage --
  5430.  *
  5431.  *      Perform machine dependent locking of a kernel resident file cache
  5432.  *    page.
  5433.  *
  5434.  * Results:
  5435.  *      None.
  5436.  *
  5437.  * Side effects:
  5438.  *
  5439.  * ----------------------------------------------------------------------------
  5440.  */
  5441. void
  5442. VmMach_LockCachePage(kernelAddress)
  5443.     Address    kernelAddress;    /* Address on page to lock. */
  5444. {
  5445.     Vm_VirtAddr    virtAddr;
  5446.     register  VMMACH_SEG_NUM    *segTablePtr, pmeg;
  5447.     register  int        hardSeg;
  5448.     Vm_PTE    *ptePtr;
  5449.     VmMachPTE        hardPTE;
  5450.     /*
  5451.      * Ignore pages not in cache pmeg range.
  5452.      */
  5453.     if (!IN_FILE_CACHE_SEG(kernelAddress)) {
  5454.     return;
  5455.     }
  5456.  
  5457.     MASTER_LOCK(vmMachMutexPtr);
  5458.  
  5459.     pmeg = VmMachGetSegMap(kernelAddress);
  5460.     if (pmeg == VMMACH_INV_PMEG) {
  5461.     int    oldContext, i;
  5462.     unsigned int a;
  5463.     /*
  5464.      *  If not a valid PMEG install a new pmeg and load its mapping. 
  5465.      */
  5466.     virtAddr.segPtr = vm_SysSegPtr;
  5467.     virtAddr.page = ((unsigned int) kernelAddress) >> VMMACH_PAGE_SHIFT;
  5468.     virtAddr.offset = 0;
  5469.     virtAddr.flags = 0;
  5470.     virtAddr.sharedPtr = (Vm_SegProcList *) NIL;
  5471.     
  5472.     hardSeg = PageToOffSeg(virtAddr.page, (&virtAddr));
  5473.     segTablePtr = (VMMACH_SEG_NUM *) 
  5474.                 GetHardSegPtr(vm_SysSegPtr->machPtr, hardSeg);
  5475.     if (*segTablePtr != VMMACH_INV_PMEG) {
  5476.         panic("VmMach_LockCachePage: Bad segTable entry.\n");
  5477.     }
  5478.     *segTablePtr = pmeg = PMEGGet(vm_SysSegPtr, hardSeg, 0);
  5479.     /*
  5480.      * Have to propagate the PMEG to all contexts.
  5481.      */
  5482.     oldContext = VmMachGetContextReg();
  5483.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  5484.         VmMachSetContextReg(i);
  5485.         VmMachSetSegMap(kernelAddress, pmeg);
  5486.     }
  5487.     VmMachSetContextReg(oldContext);
  5488.     /*
  5489.      * Reload the entire PMEG.
  5490.      */
  5491.     a = (hardSeg << VMMACH_SEG_SHIFT);
  5492.     for (i = 0; i < VMMACH_NUM_PAGES_PER_SEG; i++ ) { 
  5493.         ptePtr = VmGetPTEPtr(vm_SysSegPtr, (a >> VMMACH_PAGE_SHIFT));
  5494.         if ((*ptePtr & VM_PHYS_RES_BIT)) {
  5495.         hardPTE = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT | 
  5496.                 VirtToPhysPage(Vm_GetPageFrame(*ptePtr));
  5497.         SET_ALL_PAGE_MAP(a, hardPTE);
  5498.         if (pmeg==VMMACH_INV_PMEG) {
  5499.             panic("Invalid pmeg\n");
  5500.         }
  5501.         pmegArray[pmeg].pageCount++;
  5502.          }
  5503.          a += VMMACH_PAGE_SIZE;
  5504.     }
  5505.     }
  5506.     pmegArray[pmeg].lockCount++;
  5507.  
  5508.     MASTER_UNLOCK(vmMachMutexPtr);
  5509.     return;
  5510. }
  5511.  
  5512. /*
  5513.  * ----------------------------------------------------------------------------
  5514.  *
  5515.  * VmMach_UnlockCachePage --
  5516.  *
  5517.  *      Perform machine dependent unlocking of a kernel resident page.
  5518.  *
  5519.  * Results:
  5520.  *      None.
  5521.  *
  5522.  * Side effects:
  5523.  *
  5524.  * ----------------------------------------------------------------------------
  5525.  */
  5526. void
  5527. VmMach_UnlockCachePage(kernelAddress)
  5528.     Address    kernelAddress;    /* Address on page to unlock. */
  5529. {
  5530.     register  VMMACH_SEG_NUM    pmeg;
  5531.  
  5532.     if (!IN_FILE_CACHE_SEG(kernelAddress)) {
  5533.     return;
  5534.     }
  5535.  
  5536.     MASTER_LOCK(vmMachMutexPtr);
  5537.  
  5538.     pmeg = VmMachGetSegMap(kernelAddress);
  5539.  
  5540.     pmegArray[pmeg].lockCount--;
  5541.     if (pmegArray[pmeg].lockCount < 0) {
  5542.     panic("VmMach_UnlockCachePage lockCount < 0\n");
  5543.     }
  5544.  
  5545.     MASTER_UNLOCK(vmMachMutexPtr);
  5546.     return;
  5547. }
  5548.  
  5549. /*
  5550.  * ----------------------------------------------------------------------------
  5551.  *
  5552.  * VmMach_FlushCurrentContext --
  5553.  *
  5554.  *    Flush the current context from the cache.
  5555.  *
  5556.  *    void VmMach_FlushCurrentContext()
  5557.  *
  5558.  * Results:
  5559.  *    None.
  5560.  *
  5561.  * Side effects:
  5562.  *    All data cached from the current context is flushed from the cache.
  5563.  *
  5564.  * ----------------------------------------------------------------------------
  5565.  */
  5566. void
  5567. VmMach_FlushCurrentContext()
  5568. {
  5569.     if (vmMachHasVACache) {
  5570.     VmMachFlushCurrentContext();
  5571.     }
  5572. }
  5573.  
  5574. /*
  5575.  * ----------------------------------------------------------------------
  5576.  *
  5577.  * Vm_TouchPages --
  5578.  *
  5579.  *    Touch the range of pages.
  5580.  *
  5581.  *    ReturnStatus
  5582.  *    Vm_TouchPages(firstPage, numPages)
  5583.  *        int    firstPage;    First page to touch.
  5584.  *        int    numPages;    Number of pages to touch.
  5585.  *
  5586.  * Results:
  5587.  *    None.
  5588.  *
  5589.  * Side effects:
  5590.  *    None.
  5591.  *
  5592.  * ----------------------------------------------------------------------
  5593.  */
  5594. ReturnStatus
  5595. Vm_TouchPages(firstPage, numPages)
  5596.     int firstPage, numPages;
  5597. {
  5598.     return VmMachTouchPages(firstPage * VMMACH_CLUSTER_SIZE,
  5599.     numPages * VMMACH_CLUSTER_SIZE);
  5600. }
  5601.